diff --git a/CMakeLists.txt b/CMakeLists.txt index 1eaf2d0bbf2e0723e145e4ae18244d3c70a4d291..127cc11017ea1a2bc799b595cf75d59ac9ade0ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,522 +1,512 @@ -cmake_minimum_required(VERSION 2.6) -project(libtransport) - -message(STATUS "Variables to override default places where to find libraries:") -message(STATUS "|- cppunit : -DCPPUNIT_INCLUDE_DIR, -DCPPUNIT_LIBRARY") -message(STATUS "|- swiften : -DSWIFTEN_INCLUDE_DIR, -DSWIFTEN_LIBRARY") -message(STATUS " |- zlib : -DZLIB_LIBRARY") -message(STATUS " |- expat : -DEXPAT_LIBRARY") -message(STATUS " |-libidn : -DLIBIDN_LIBRARY") -message(STATUS " |-libxml : -DLIBXML_LIBRARY") -message(STATUS "|- boost : -DBOOST_INCLUDEDIR, -DBOOST_LIBRARYDIR") -message(STATUS "|- protobuf: -DPROTOBUF_INCLUDE_DIR, -DPROTOBUF_LIBRARY") -message(STATUS " : -DPROTOBUF_PROTOC_EXECUTABLE") -message(STATUS "|- log4cxx : -DLOG4CXX_INCLUDE_DIR, -DLOG4CXX_LIBRARY") -message(STATUS "|- purple : -DPURPLE_INCLUDE_DIR, -DPURPLE_LIBRARY") -message(STATUS " : -DPURPLE_NOT_RUNTIME - enables compilation with libpurple.lib") - -option(ENABLE_SQLITE3 "Build with SQLite3 support" ON) -option(ENABLE_MYSQL "Build with MySQL support" ON) -option(ENABLE_PQXX "Build with Postgres supoort" ON) - -option(ENABLE_FROTZ "Build Frotz plugin" ON) -option(ENABLE_IRC "Build IRC plugin" ON) -option(ENABLE_PURPLE "Build Libpurple plugin" ON) -option(ENABLE_SMSTOOLS3 "Build SMSTools3 plugin" ON) -option(ENABLE_SKYPE "Build Skype plugin" ON) -option(ENABLE_SWIFTEN "Build Swiften plugin" ON) -option(ENABLE_TWITTER "Build Twitter plugin" ON) -option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) - -option(ENABLE_DOCS "Build Docs" ON) -# option(ENABLE_LOG "Build with logging using Log4cxx" ON) -option(ENABLE_TESTS "Build Tests using CppUnit" OFF) - -MACRO(LIST_CONTAINS var value) - SET(${var}) - FOREACH (value2 ${ARGN}) - IF (${value} STREQUAL ${value2}) - SET(${var} TRUE) - ENDIF (${value} STREQUAL ${value2}) - ENDFOREACH (value2) -ENDMACRO(LIST_CONTAINS) - -if(NOT LIB_INSTALL_DIR) - set(LIB_INSTALL_DIR "lib") -endif() - -set(CMAKE_MODULE_PATH "cmake_modules") - -###### Prerequisites ###### - - -# FIND SWIFTEN - -set(Swiften_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(Swiften) - -if(NOT SWIFTEN_FOUND) - if (ZLIB_LIBRARY) - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${ZLIB_LIBRARY}) - endif() - if (EXPAT_LIBRARY) - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${EXPAT_LIBRARY}) - endif() - if (LIBIDN_LIBRARY) - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${LIBIDN_LIBRARY}) - endif() - if (LIBXML_LIBRARY) - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${LIBXML_LIBRARY}) - endif() - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Dnsapi") - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Crypt32") - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Secur32") - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Iphlpapi") - set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Winscard") - message(STATUS "Using swiften: ${SWIFTEN_INCLUDE_DIR} ${SWIFTEN_LIBRARY}") -endif() - -# FIND BOOST -if (WIN32) - set(Boost_USE_STATIC_LIBS ON) - set(Boost_USE_MULTITHREADED ON) - set(Boost_USE_STATIC_RUNTIME OFF) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) -else(WIN32) - LIST_CONTAINS(contains -lboost_program_options ${SWIFTEN_LIBRARY}) - if(contains) - message(STATUS "Using non-multithreaded boost") - set(Boost_USE_MULTITHREADED 0) - endif(contains) - set(Boost_FIND_QUIETLY ON) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals) - if (NOT Boost_FOUND) - set(Boost_FIND_QUIETLY OFF) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) - endif() -endif(WIN32) - -message( STATUS "Found Boost: ${Boost_VERSION}, ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}") - -if (${Boost_VERSION} GREATER 104999) - message( STATUS "Using BOOST_FILESYSTEM_VERSION=3") - add_definitions(-DBOOST_FILESYSTEM_VERSION=3) -endif() - -# FIND POPT -if (NOT WIN32) - set(popt_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(popt REQUIRED) -endif() - -###### Database ###### - -# FIND SQLITE3 -if (ENABLE_SQLITE3) - if (MSVC) - set(SQLITE3_FOUND 1) - ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps) - else() - if (WIN32) - ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3) - else() - set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(sqlite3) - endif() - endif() -endif() - -# FIND MYSQL -if(ENABLE_MYSQL) - set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(mysql) -endif() - -# FIND PQXX -if(ENABLE_PQXX) - set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(pqxx) -endif() - -###### Plugins ###### - -# FIND LIBPURPLE -if(ENABLE_PURPLE) - set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(purple) - - if (WIN32) - if (PURPLE_NOT_RUNTIME) - add_definitions(-DPURPLE_RUNTIME=0) - else(PURPLE_NOT_RUNTIME) - add_definitions(-DPURPLE_RUNTIME=1) - endif(PURPLE_NOT_RUNTIME) - else() - add_definitions(-DPURPLE_RUNTIME=0) - endif() - - # FIND LIBEVENT - set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(event) -endif() - -# FIND GLIB -if(ENABLE_SKYPE OR ENABLE_PURPLE) -# if (GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) -# set(GLIB2_FOUND TRUE) -# else() - set(glib_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(glib) -# endif() -endif() - -# FIND LIBXML2 -# set(libxml2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -# find_package(libxml2) - -# FIND PROTOBUF -set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(Protobuf REQUIRED) - -if (NOT PROTOBUF_FOUND AND PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY) - set(PROTOBUF_FOUND 1) - set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) - if (PROTOBUF_PROTOC_EXECUTABLE) - else() - set(PROTOBUF_PROTOC_EXECUTABLE protoc) - endif() - message(STATUS "Using protobuf: ${PROTOBUF_INCLUDE_DIRS} ${PROTOBUF_LIBRARY}") -endif() - -if (WIN32) - add_definitions(-DSWIFTEN_STATIC=1) - ADD_DEFINITIONS(-D_UNICODE) - ADD_DEFINITIONS(-DUNICODE) -endif() - - -if (CMAKE_COMPILER_IS_GNUCXX) -set(openssl_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(openssl) -endif() - -if(ENABLE_IRC) - set(Communi_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(Communi) - - INCLUDE(FindQt4) - FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork) - # ADD_DEFINITIONS(${SWIFTEN_CFLAGS}) - ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS) - # ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2) -endif() - -set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(event) - -if (NOT WIN32 AND ENABLE_SKYPE) -set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(dbus) -endif() - -# if(ENABLE_YAHOO2) -# set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -# find_package(yahoo2) -# endif() - -####### Miscallanous ###### - -if(ENABLE_DOCS) - find_package(Doxygen) -endif() - -# if(ENABLE_LOG) - if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY) - set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY}) - set(LOG4CXX_FOUND 1) - message(STATUS "Using log4cxx: ${CPPUNIT_INCLUDE_DIR} ${LOG4CXX_INCLUDE_DIR}") - else() - set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(log4cxx) - endif() -# endif() - -# FIND CPPUNIT -if(ENABLE_TESTS) - set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(cppunit) - - if(NOT CPPUNIT_FOUND AND CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY) - set(CCPUNIT_LIBRARIES ${CPPUNIT_LIBRARY}) - set(CPPUNIT_FOUND 1) - message(STATUS "Using cppunit: ${CPPUNIT_INCLUDE_DIR} ${CPPUNIT_LIBRARIES}") - endif() -endif() - -if (APPLE) - FIND_LIBRARY(IOKIT_FRAMEWORK IOKit) - FIND_LIBRARY(SECURITY_FRAMEWORK Security) - FIND_LIBRARY(APPKIT_FRAMEWORK AppKit) - FIND_LIBRARY(SYSTEMCONFIGURATION_FRAMEWORK SystemConfiguration) - FIND_LIBRARY(SECURITYINTERFACE_FRAMEWORK SecurityInterface) - MARK_AS_ADVANCED(IOKIT_FRAMEWORK APPKIT_FRAMEWORK SYSTEMCONFIGURATION_FRAMEWORK SECURITY_FRAMEWORK SECURITYINTERFACE_FRAMEWORK) - SET (APPLE_FRAMEWORKS ${IOKIT_FRAMEWORK} ${APPKIT_FRAMEWORK} ${SYSTEMCONFIGURATION_FRAMEWORK} ${SECURITY_FRAMEWORK} ${SECURITYINTERFACE_FRAMEWORK}) -endif() - -message(" Supported features") -message("-----------------------") - -if (SPECTRUM_VERSION) - ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}") -else (SPECTRUM_VERSION) - if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) - if (NOT GIT_EXECUTABLE) - set (GIT_EXECUTABLE git) - endif() - execute_process(COMMAND ${GIT_EXECUTABLE} "--git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git" rev-parse --short HEAD - OUTPUT_VARIABLE GIT_REVISION - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - set(SPECTRUM_VERSION 2.0.0-beta-git-${GIT_REVISION}) - ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}") - else (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) - set(SPECTRUM_VERSION 2.0.0-alpha) - ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}") - endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) -endif (SPECTRUM_VERSION) - -message("Version : " ${SPECTRUM_VERSION}) - -if (SQLITE3_FOUND) - ADD_DEFINITIONS(-DWITH_SQLITE) - include_directories(${SQLITE3_INCLUDE_DIR}) - message("SQLite3 : yes") -else (SQLITE3_FOUND) - if (WIN32) - ADD_DEFINITIONS(-DWITH_SQLITE) - include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3") - message("SQLite3 : bundled") - else() - set(SQLITE3_LIBRARIES "") - if(ENABLE_SQLITE3) - message("SQLite3 : no (install sqlite3)") - else(ENABLE_SQLITE3) - message("SQLite3 : no (user disabled)") - endif() - endif() -endif (SQLITE3_FOUND) - -if (MYSQL_FOUND) - ADD_DEFINITIONS(-DWITH_MYSQL) - include_directories(${MYSQL_INCLUDE_DIR}) - message("MySQL : yes") -else (MYSQL_FOUND) - set(MYSQL_LIBRARIES "") - if(ENABLE_MYSQL) - message("MySQL : no (install mysql-devel)") - else(ENABLE_MYSQL) - message("MySQL : no (user disabled)") - endif() -endif (MYSQL_FOUND) - -if (PQXX_FOUND) - ADD_DEFINITIONS(-DWITH_PQXX) - include_directories(${PQXX_INCLUDE_DIR}) - message("PostgreSQL : yes") -else (PQXX_FOUND) - set(PQXX_LIBRARY "") - set(PQ_LIBRARY "") - if(ENABLE_PQXX) - message("PostgreSQL : no (install libpqxx-devel)") - else(ENABLE_PQXX) - message("PostgreSQL : no (user disabled)") - endif() -endif (PQXX_FOUND) - -if (PROTOBUF_FOUND) - ADD_DEFINITIONS(-DWITH_PROTOBUF) - include_directories(${PROTOBUF_INCLUDE_DIRS}) - message("Network plugins : yes") - - if(PURPLE_FOUND) - message("Libpurple plugin : yes") - include_directories(${PURPLE_INCLUDE_DIR}) - include_directories(${GLIB2_INCLUDE_DIR}) - else() - if(ENABLE_PURPLE) - message("Libpurple plugin : no (install libpurple)") - else(ENABLE_PURPLE) - message("Libpurple plugin : no (user disabled)") - endif() - endif() - - if (HAVE_EVENT) - ADD_DEFINITIONS(-DWITH_LIBEVENT) - include_directories(${EVENT_INCLUDE_DIRS}) - message(" libev eventloop : yes") - else() - if(ENABLE_PURPLE) - message(" libev eventloop : no (install libev-devel)") - endif() - endif() - - if(IRC_FOUND) - ADD_DEFINITIONS(-DCOMMUNI_SHARED) - message("IRC plugin : yes") - include_directories(${QT_QTNETWORK_INCLUDE_DIR}) - include_directories(${IRC_INCLUDE_DIR}) - include(${QT_USE_FILE}) - else() - if(ENABLE_IRC) - message("IRC plugin : no (install libCommuni and libprotobuf-dev)") - else(ENABLE_IRC) - message("IRC plugin : no (user disabled)") - endif() - endif() - if(ENABLE_TWITTER) - message("Twitter plugin : yes") - else(ENABLE_TWITTER) - message("Twitter plugin : no (user disabled)") - endif() - if (NOT WIN32) - if(ENABLE_FROTZ) - message("Frotz plugin : yes") - else() - message("Frotz plugin : no (user disabled)") - endif() - if(ENABLE_SMSTOOLS3) - message("SMSTools3 plugin : yes") - else() - message("SMSTools3 plugin : no (user disabled)") - endif() - if(${LIBDBUSGLIB_FOUND}) - message("Skype plugin : yes") - include_directories(${LIBDBUSGLIB_INCLUDE_DIRS}) - else() - if(ENABLE_SKYPE) - message("Skype plugin : no (install dbus-glib-devel)") - else(ENABLE_SKYPE) - message("Skype plugin : no (user disabled)") - endif() - endif() - else() - message("Frotz plugin : no (does not run on Win32)") - message("SMSTools3 plugin : no (does not run on Win32)") - message("Skype plugin : no (does not run on Win32)") - endif() - -# if(YAHOO2_FOUND) -# message("Libyahoo2 plugin : yes") -# include_directories(${YAHOO2_INCLUDE_DIR}) -# else() - if(ENABLE_YAHOO2) - set(YAHOO2_FOUND 1) - message("Libyahoo2 plugin : yes") - else(ENABLE_YAHOO2) - message("Libyahoo2 plugin : no (user disabled)") - endif() -# endif() - - if(ENABLE_SWIFTEN) - message("Swiften plugin : yes") - else() - message("Swiften plugin : no (user disabled)") - endif() -else() - message("Network plugins : no (install libprotobuf-dev)") - message("Libpurple plugin : no (install libpurple and libprotobuf-dev)") - message("IRC plugin : no (install libircclient-qt and libprotobuf-dev)") - message("Frotz plugin : no (install libprotobuf-dev)") - message("SMSTools3 plugin : no (install libprotobuf-dev)") - message("Swiften plugin : no (install libprotobuf-dev)") - message("Twitter plugin : no (install libprotobuf-dev)") -endif() - -if (LOG4CXX_FOUND) - message("Log4cxx : yes") - include_directories(${LOG4CXX_INCLUDE_DIR}) - ADD_DEFINITIONS(-DWITH_LOG4CXX) -else() - set(LOG4CXX_LIBRARIES "") - if (WIN32) - message("Log4cxx : no (install log4cxx-devel)") - else() - message(FATAL_ERROR "Log4cxx : no (install log4cxx-devel)") - endif() -endif() - -if (WIN32) - ADD_DEFINITIONS(-DLOG4CXX_STATIC) - ADD_DEFINITIONS(-D_WIN32_WINNT=0x501) - ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN) - ADD_DEFINITIONS(-DBOOST_USE_WINDOWS_H) - ADD_DEFINITIONS(-DBOOST_THREAD_USE_LIB) -endif() - -if(CMAKE_BUILD_TYPE MATCHES Debug) - if (CMAKE_COMPILER_IS_GNUCXX) - ADD_DEFINITIONS(-O0) - ADD_DEFINITIONS(-ggdb) - endif() - ADD_DEFINITIONS(-DDEBUG) - message("Debug : yes") -else(CMAKE_BUILD_TYPE MATCHES Debug) - message("Debug : no (run \"cmake . -DCMAKE_BUILD_TYPE=Debug\")") -endif(CMAKE_BUILD_TYPE MATCHES Debug) - - -SET(TRANSPORT_VERSION 2.0) -SET(PROJECT_VERSION 2.0) -include_directories(include) - - -include_directories(${EVENT_INCLUDE_DIRS}) -include_directories(${SWIFTEN_INCLUDE_DIR}) -include_directories(${Boost_INCLUDE_DIRS}) - -if (CMAKE_COMPILER_IS_GNUCXX) -include_directories(${OPENSSL_INCLUDE_DIR}) -endif() - -ADD_SUBDIRECTORY(src) -ADD_SUBDIRECTORY(plugin) -ADD_SUBDIRECTORY(include) -ADD_SUBDIRECTORY(spectrum) -ADD_SUBDIRECTORY(backends) -if (NOT WIN32) - ADD_SUBDIRECTORY(spectrum_manager) -# ADD_SUBDIRECTORY(spectrum2_send_message) -endif() - -if (CPPUNIT_FOUND) - message("tests : yes") - include_directories(${CPPUNIT_INCLUDE_DIR}) -else() - if(ENABLE_TESTS) - message("tests : no (install CPPUnit)") - else(ENABLE_TESTS) - message("tests : no (user disabled)") - endif() -endif() - -if(DOXYGEN_FOUND) - message("Docs : yes") - ADD_SUBDIRECTORY(docs) -else(DOXYGEN_FOUND) - if(ENABLE_DOCS) - message("Docs : no (install doxygen)") - else(ENABLE_DOCS) - message("Docs : no (user disabled)") - endif() -endif(DOXYGEN_FOUND) - -message("----------------------") - -if(NOT SQLITE3_FOUND AND NOT MYSQL_FOUND AND NOT PQXX_FOUND) - if(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX) - message("Could not find any database - Please install at least one of sqlite3-devel, mysql-devel or pqxx-devel if you want to use transport mode.") - else(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX) - message("Please enable at least one of SQLITE3, MYSQL, PQXX databases to use transport mode.") - endif() -endif() - +cmake_minimum_required(VERSION 2.6) +project(libtransport) + +message(STATUS "Variables to override default places where to find libraries:") +message(STATUS "|- cppunit : -DCPPUNIT_INCLUDE_DIR, -DCPPUNIT_LIBRARY") +message(STATUS "|- swiften : -DSWIFTEN_INCLUDE_DIR, -DSWIFTEN_LIBRARY") +message(STATUS " |- zlib : -DZLIB_LIBRARY") +message(STATUS " |- expat : -DEXPAT_LIBRARY") +message(STATUS " |-libidn : -DLIBIDN_LIBRARY") +message(STATUS " |-libxml : -DLIBXML_LIBRARY") +message(STATUS "|- boost : -DBOOST_INCLUDEDIR, -DBOOST_LIBRARYDIR") +message(STATUS "|- protobuf: -DPROTOBUF_INCLUDE_DIR, -DPROTOBUF_LIBRARY") +message(STATUS " : -DPROTOBUF_PROTOC_EXECUTABLE") +message(STATUS "|- log4cxx : -DLOG4CXX_INCLUDE_DIR, -DLOG4CXX_LIBRARY") +message(STATUS "|- purple : -DPURPLE_INCLUDE_DIR, -DPURPLE_LIBRARY") +message(STATUS " : -DPURPLE_NOT_RUNTIME - enables compilation with libpurple.lib") + +option(ENABLE_SQLITE3 "Build with SQLite3 support" ON) +option(ENABLE_MYSQL "Build with MySQL support" ON) +option(ENABLE_PQXX "Build with Postgres supoort" ON) + +option(ENABLE_FROTZ "Build Frotz plugin" ON) +option(ENABLE_IRC "Build IRC plugin" ON) +option(ENABLE_PURPLE "Build Libpurple plugin" ON) +option(ENABLE_SMSTOOLS3 "Build SMSTools3 plugin" ON) +option(ENABLE_SKYPE "Build Skype plugin" ON) +option(ENABLE_SWIFTEN "Build Swiften plugin" ON) +option(ENABLE_TWITTER "Build Twitter plugin" ON) +option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) + +option(ENABLE_DOCS "Build Docs" ON) +# option(ENABLE_LOG "Build with logging using Log4cxx" ON) +option(ENABLE_TESTS "Build Tests using CppUnit" OFF) + +MACRO(LIST_CONTAINS var value) + SET(${var}) + FOREACH (value2 ${ARGN}) + IF (${value} STREQUAL ${value2}) + SET(${var} TRUE) + ENDIF (${value} STREQUAL ${value2}) + ENDFOREACH (value2) +ENDMACRO(LIST_CONTAINS) + +if(NOT LIB_INSTALL_DIR) + set(LIB_INSTALL_DIR "lib") +endif() + +set(CMAKE_MODULE_PATH "cmake_modules") + +###### Prerequisites ###### + + +# FIND SWIFTEN + +set(Swiften_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(Swiften) + +if(NOT SWIFTEN_FOUND) + if (ZLIB_LIBRARY) + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${ZLIB_LIBRARY}) + endif() + if (EXPAT_LIBRARY) + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${EXPAT_LIBRARY}) + endif() + if (LIBIDN_LIBRARY) + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${LIBIDN_LIBRARY}) + endif() + if (LIBXML_LIBRARY) + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} ${LIBXML_LIBRARY}) + endif() + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Dnsapi") + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Crypt32") + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Secur32") + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Iphlpapi") + set(SWIFTEN_LIBRARY ${SWIFTEN_LIBRARY} "Winscard") + message(STATUS "Using swiften: ${SWIFTEN_INCLUDE_DIR} ${SWIFTEN_LIBRARY}") +endif() + +# FIND BOOST +if (WIN32) + set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_MULTITHREADED ON) + set(Boost_USE_STATIC_RUNTIME OFF) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) +else(WIN32) + LIST_CONTAINS(contains -lboost_program_options ${SWIFTEN_LIBRARY}) + if(contains) + message(STATUS "Using non-multithreaded boost") + set(Boost_USE_MULTITHREADED 0) + endif(contains) + set(Boost_FIND_QUIETLY ON) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals) + if (NOT Boost_FOUND) + set(Boost_FIND_QUIETLY OFF) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) + endif() +endif(WIN32) + +message( STATUS "Found Boost: ${Boost_VERSION}, ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}") + +if (${Boost_VERSION} GREATER 104999) + message( STATUS "Using BOOST_FILESYSTEM_VERSION=3") + add_definitions(-DBOOST_FILESYSTEM_VERSION=3) +endif() + +# FIND POPT +if (NOT WIN32) + set(popt_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(popt REQUIRED) +endif() + +###### Database ###### + +# FIND SQLITE3 +if (ENABLE_SQLITE3) + if (MSVC) + set(SQLITE3_FOUND 1) + ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps) + else() + if (WIN32) + ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3) + else() + set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(sqlite3) + endif() + endif() +endif() + +# FIND MYSQL +if(ENABLE_MYSQL) + set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(mysql) +endif() + +# FIND PQXX +if(ENABLE_PQXX) + set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(pqxx) +endif() + +###### Plugins ###### + +# FIND LIBPURPLE +if(ENABLE_PURPLE) + set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(purple) + + if (WIN32) + if (PURPLE_NOT_RUNTIME) + add_definitions(-DPURPLE_RUNTIME=0) + else(PURPLE_NOT_RUNTIME) + add_definitions(-DPURPLE_RUNTIME=1) + endif(PURPLE_NOT_RUNTIME) + else() + add_definitions(-DPURPLE_RUNTIME=0) + endif() + + # FIND LIBEVENT + set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(event) +endif() + +# FIND GLIB +if(ENABLE_SKYPE OR ENABLE_PURPLE) +# if (GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) +# set(GLIB2_FOUND TRUE) +# else() + set(glib_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(glib) +# endif() +endif() + +# FIND LIBXML2 +# set(libxml2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +# find_package(libxml2) + +# FIND PROTOBUF +set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(Protobuf REQUIRED) + +if (NOT PROTOBUF_FOUND AND PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY) + set(PROTOBUF_FOUND 1) + set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) + if (PROTOBUF_PROTOC_EXECUTABLE) + else() + set(PROTOBUF_PROTOC_EXECUTABLE protoc) + endif() + message(STATUS "Using protobuf: ${PROTOBUF_INCLUDE_DIRS} ${PROTOBUF_LIBRARY}") +endif() + +if (WIN32) + add_definitions(-DSWIFTEN_STATIC=1) + ADD_DEFINITIONS(-D_UNICODE) + ADD_DEFINITIONS(-DUNICODE) +endif() + + +if (CMAKE_COMPILER_IS_GNUCXX) +set(openssl_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(openssl) +endif() + +if(ENABLE_IRC) + set(Communi_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(Communi) + + INCLUDE(FindQt4) + FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork) + # ADD_DEFINITIONS(${SWIFTEN_CFLAGS}) + ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS) + # ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2) +endif() + +set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(event) + +if (NOT WIN32 AND ENABLE_SKYPE) +set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(dbus) +endif() + +# if(ENABLE_YAHOO2) +# set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +# find_package(yahoo2) +# endif() + +####### Miscallanous ###### + +if(ENABLE_DOCS) + find_package(Doxygen) +endif() + +# if(ENABLE_LOG) + if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY) + set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY}) + set(LOG4CXX_FOUND 1) + message(STATUS "Using log4cxx: ${CPPUNIT_INCLUDE_DIR} ${LOG4CXX_INCLUDE_DIR}") + else() + set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(log4cxx) + endif() +# endif() + +# FIND CPPUNIT +if(ENABLE_TESTS) + set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(cppunit) + + if(NOT CPPUNIT_FOUND AND CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY) + set(CCPUNIT_LIBRARIES ${CPPUNIT_LIBRARY}) + set(CPPUNIT_FOUND 1) + message(STATUS "Using cppunit: ${CPPUNIT_INCLUDE_DIR} ${CPPUNIT_LIBRARIES}") + endif() +endif() + +message(" Supported features") +message("-----------------------") + +if (SPECTRUM_VERSION) + ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}") +else (SPECTRUM_VERSION) + if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + if (NOT GIT_EXECUTABLE) + set (GIT_EXECUTABLE git) + endif() + execute_process(COMMAND ${GIT_EXECUTABLE} "--git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git" rev-parse --short HEAD + OUTPUT_VARIABLE GIT_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(SPECTRUM_VERSION 2.0.0-beta-git-${GIT_REVISION}) + ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}") + else (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + set(SPECTRUM_VERSION 2.0.0-alpha) + ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}") + endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) +endif (SPECTRUM_VERSION) + +message("Version : " ${SPECTRUM_VERSION}) + +if (SQLITE3_FOUND) + ADD_DEFINITIONS(-DWITH_SQLITE) + include_directories(${SQLITE3_INCLUDE_DIR}) + message("SQLite3 : yes") +else (SQLITE3_FOUND) + if (WIN32) + ADD_DEFINITIONS(-DWITH_SQLITE) + include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3") + message("SQLite3 : bundled") + else() + set(SQLITE3_LIBRARIES "") + if(ENABLE_SQLITE3) + message("SQLite3 : no (install sqlite3)") + else(ENABLE_SQLITE3) + message("SQLite3 : no (user disabled)") + endif() + endif() +endif (SQLITE3_FOUND) + +if (MYSQL_FOUND) + ADD_DEFINITIONS(-DWITH_MYSQL) + include_directories(${MYSQL_INCLUDE_DIR}) + message("MySQL : yes") +else (MYSQL_FOUND) + set(MYSQL_LIBRARIES "") + if(ENABLE_MYSQL) + message("MySQL : no (install mysql-devel)") + else(ENABLE_MYSQL) + message("MySQL : no (user disabled)") + endif() +endif (MYSQL_FOUND) + +if (PQXX_FOUND) + ADD_DEFINITIONS(-DWITH_PQXX) + include_directories(${PQXX_INCLUDE_DIR}) + message("PostgreSQL : yes") +else (PQXX_FOUND) + set(PQXX_LIBRARY "") + set(PQ_LIBRARY "") + if(ENABLE_PQXX) + message("PostgreSQL : no (install libpqxx-devel)") + else(ENABLE_PQXX) + message("PostgreSQL : no (user disabled)") + endif() +endif (PQXX_FOUND) + +if (PROTOBUF_FOUND) + ADD_DEFINITIONS(-DWITH_PROTOBUF) + include_directories(${PROTOBUF_INCLUDE_DIRS}) + message("Network plugins : yes") + + if(PURPLE_FOUND) + message("Libpurple plugin : yes") + include_directories(${PURPLE_INCLUDE_DIR}) + include_directories(${GLIB2_INCLUDE_DIR}) + else() + if(ENABLE_PURPLE) + message("Libpurple plugin : no (install libpurple)") + else(ENABLE_PURPLE) + message("Libpurple plugin : no (user disabled)") + endif() + endif() + + if (HAVE_EVENT) + ADD_DEFINITIONS(-DWITH_LIBEVENT) + include_directories(${EVENT_INCLUDE_DIRS}) + message(" libev eventloop : yes") + else() + if(ENABLE_PURPLE) + message(" libev eventloop : no (install libev-devel)") + endif() + endif() + + if(IRC_FOUND) + ADD_DEFINITIONS(-DCOMMUNI_SHARED) + message("IRC plugin : yes") + include_directories(${QT_QTNETWORK_INCLUDE_DIR}) + include_directories(${IRC_INCLUDE_DIR}) + include(${QT_USE_FILE}) + else() + if(ENABLE_IRC) + message("IRC plugin : no (install libCommuni and libprotobuf-dev)") + else(ENABLE_IRC) + message("IRC plugin : no (user disabled)") + endif() + endif() + if(ENABLE_TWITTER) + message("Twitter plugin : yes") + else(ENABLE_TWITTER) + message("Twitter plugin : no (user disabled)") + endif() + if (NOT WIN32) + if(ENABLE_FROTZ) + message("Frotz plugin : yes") + else() + message("Frotz plugin : no (user disabled)") + endif() + if(ENABLE_SMSTOOLS3) + message("SMSTools3 plugin : yes") + else() + message("SMSTools3 plugin : no (user disabled)") + endif() + if(${LIBDBUSGLIB_FOUND}) + message("Skype plugin : yes") + include_directories(${LIBDBUSGLIB_INCLUDE_DIRS}) + else() + if(ENABLE_SKYPE) + message("Skype plugin : no (install dbus-glib-devel)") + else(ENABLE_SKYPE) + message("Skype plugin : no (user disabled)") + endif() + endif() + else() + message("Frotz plugin : no (does not run on Win32)") + message("SMSTools3 plugin : no (does not run on Win32)") + message("Skype plugin : no (does not run on Win32)") + endif() + +# if(YAHOO2_FOUND) +# message("Libyahoo2 plugin : yes") +# include_directories(${YAHOO2_INCLUDE_DIR}) +# else() + if(ENABLE_YAHOO2) + set(YAHOO2_FOUND 1) + message("Libyahoo2 plugin : yes") + else(ENABLE_YAHOO2) + message("Libyahoo2 plugin : no (user disabled)") + endif() +# endif() + + if(ENABLE_SWIFTEN) + message("Swiften plugin : yes") + else() + message("Swiften plugin : no (user disabled)") + endif() +else() + message("Network plugins : no (install libprotobuf-dev)") + message("Libpurple plugin : no (install libpurple and libprotobuf-dev)") + message("IRC plugin : no (install libircclient-qt and libprotobuf-dev)") + message("Frotz plugin : no (install libprotobuf-dev)") + message("SMSTools3 plugin : no (install libprotobuf-dev)") + message("Swiften plugin : no (install libprotobuf-dev)") + message("Twitter plugin : no (install libprotobuf-dev)") +endif() + +if (LOG4CXX_FOUND) + message("Log4cxx : yes") + include_directories(${LOG4CXX_INCLUDE_DIR}) + ADD_DEFINITIONS(-DWITH_LOG4CXX) +else() + set(LOG4CXX_LIBRARIES "") + if (WIN32) + message("Log4cxx : no (install log4cxx-devel)") + else() + message(FATAL_ERROR "Log4cxx : no (install log4cxx-devel)") + endif() +endif() + +if (WIN32) + ADD_DEFINITIONS(-DLOG4CXX_STATIC) + ADD_DEFINITIONS(-D_WIN32_WINNT=0x501) + ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN) + ADD_DEFINITIONS(-DBOOST_USE_WINDOWS_H) + ADD_DEFINITIONS(-DBOOST_THREAD_USE_LIB) +endif() + +if(CMAKE_BUILD_TYPE MATCHES Debug) + if (CMAKE_COMPILER_IS_GNUCXX) + ADD_DEFINITIONS(-O0) + ADD_DEFINITIONS(-ggdb) + endif() + ADD_DEFINITIONS(-DDEBUG) + message("Debug : yes") +else(CMAKE_BUILD_TYPE MATCHES Debug) + message("Debug : no (run \"cmake . -DCMAKE_BUILD_TYPE=Debug\")") +endif(CMAKE_BUILD_TYPE MATCHES Debug) + + +SET(TRANSPORT_VERSION 2.0) +SET(PROJECT_VERSION 2.0) +include_directories(include) + + +include_directories(${EVENT_INCLUDE_DIRS}) +include_directories(${SWIFTEN_INCLUDE_DIR}) +include_directories(${Boost_INCLUDE_DIRS}) + +if (CMAKE_COMPILER_IS_GNUCXX) +include_directories(${OPENSSL_INCLUDE_DIR}) +endif() + +ADD_SUBDIRECTORY(src) +ADD_SUBDIRECTORY(plugin) +ADD_SUBDIRECTORY(include) +ADD_SUBDIRECTORY(spectrum) +ADD_SUBDIRECTORY(backends) +if (NOT WIN32) + ADD_SUBDIRECTORY(spectrum_manager) +# ADD_SUBDIRECTORY(spectrum2_send_message) +endif() + +if (CPPUNIT_FOUND) + message("tests : yes") + include_directories(${CPPUNIT_INCLUDE_DIR}) +else() + if(ENABLE_TESTS) + message("tests : no (install CPPUnit)") + else(ENABLE_TESTS) + message("tests : no (user disabled)") + endif() +endif() + +if(DOXYGEN_FOUND) + message("Docs : yes") + ADD_SUBDIRECTORY(docs) +else(DOXYGEN_FOUND) + if(ENABLE_DOCS) + message("Docs : no (install doxygen)") + else(ENABLE_DOCS) + message("Docs : no (user disabled)") + endif() +endif(DOXYGEN_FOUND) + +message("----------------------") + +if(NOT SQLITE3_FOUND AND NOT MYSQL_FOUND AND NOT PQXX_FOUND) + if(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX) + message("Could not find any database - Please install at least one of sqlite3-devel, mysql-devel or pqxx-devel if you want to use transport mode.") + else(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX) + message("Please enable at least one of SQLITE3, MYSQL, PQXX databases to use transport mode.") + endif() +endif() + diff --git a/README.win32 b/README.win32 index ac932e729b3f2bde9ec0b6bed00ac60c0cebe5a1..cbcd990cd1d2320145eae1977f679221197ae80f 100644 --- a/README.win32 +++ b/README.win32 @@ -1,61 +1,61 @@ -Prerequisites -============= - -1. Microsoft Visual C++ 2010 Express or higher edition (http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express) -2. Git for Windows (http://code.google.com/p/msysgit/downloads/list) -3. CMake 2.8 or newer (http://www.cmake.org/cmake/resources/software.html) -4. Python 2.x for Swiften build scripts (scons) (http://www.python.org) - -Libraries -========= -3. Swiften library (http://swift.im/git/swift) -4. Boost 1.48 or newer (http://sourceforge.net/projects/boost/files/boost/1.49.0/) -5. Google ProtoBuf library (http://code.google.com/p/protobuf/downloads/list) - - -Environment -=========== - -To create spectrum build environment do: - -0. Create directory where we'll install all dependencies, e.g. C:\env-msvc-x64. -Create C:\env-msvc-x64\bin and add it to %PATH%. -Assuming you have git, python and cmake in %PATH%, -launch "Visual Studio 2010 command prompt" or -"Visual Studio 2010(x64) command prompt", depends on your target (Windows x86 or Windows x86_64). -1. unpack and build boost libraries: - - bootstrap.bat - b2.exe --without-mpi --without-python - b2.exe --without-mpi --without-python install --prefix=C:\env-msvc-x64 release - -2. clone swift repository and build it. Don't forget to point it to our env directory: - - git clone git://swift.im/swift - cd swift - echo boost_includedir="c:/env-msvc-x64/include/boost-1_49" > config.py - echo boost_libdir="c:/env-msvc-x64/lib" >> config.py - scons.bat debug=no SWIFTEN_INSTALLDIR=C:\env-msvc-x64 force_configure=1 - scons.bat debug=no SWIFTEN_INSTALLDIR=C:\env-msvc-x64 C:\env-msvc-x64 - -3. unpack and compile protobuf as described in its documentation. - -Run extract_includes.bat in vsprojects/ directory and move resulting vsprojects/include/google/ directory to our C:\env-msvc-x64\include - -Move protoc.exe to C:\env-msvc-x64\bin\ and libprotobuf.lib to C:\env-msvc-x64\lib - -4. Install gtkmm - -Download installer from https://live.gnome.org/gtkmm/MSWindows and install gtkmm into C:\env-msvc-x64\ - -5. Install libpurple headers - -Download http://www.pidgin.im/download/source/ , extract it and copy libpurple directory in C:\env-msvc-x64\include - -6. You're ready! :) Clone libtransport into C:\env-msvc-x64\libtransport (You *must* clone it into this directory, because libtransport will try to find the dependencies in ../lib and ../include) - -Compile it as: - - set CMAKE_INCLUDE_PATH=C:\env-msvc-x64\include - cmake . -G "NMake Makefiles" -DBOOST_INCLUDEDIR=../include/boost-1_49 -DBOOST_LIBRARYDIR=../lib -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=C:\env-msvc-x64 -DGIT_EXECUTABLE="c:\Program Files (x86)\git\bin\git.exe" - nmake +Prerequisites +============= + +1. Microsoft Visual C++ 2010 Express or higher edition (http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express) +2. Git for Windows (http://code.google.com/p/msysgit/downloads/list) +3. CMake 2.8 or newer (http://www.cmake.org/cmake/resources/software.html) +4. Python 2.x for Swiften build scripts (scons) (http://www.python.org) + +Libraries +========= +3. Swiften library (http://swift.im/git/swift) +4. Boost 1.48 or newer (http://sourceforge.net/projects/boost/files/boost/1.49.0/) +5. Google ProtoBuf library (http://code.google.com/p/protobuf/downloads/list) + + +Environment +=========== + +To create spectrum build environment do: + +0. Create directory where we'll install all dependencies, e.g. C:\env-msvc-x64. +Create C:\env-msvc-x64\bin and add it to %PATH%. +Assuming you have git, python and cmake in %PATH%, +launch "Visual Studio 2010 command prompt" or +"Visual Studio 2010(x64) command prompt", depends on your target (Windows x86 or Windows x86_64). +1. unpack and build boost libraries: + + bootstrap.bat + b2.exe --without-mpi --without-python + b2.exe --without-mpi --without-python install --prefix=C:\env-msvc-x64 release + +2. clone swift repository and build it. Don't forget to point it to our env directory: + + git clone git://swift.im/swift + cd swift + echo boost_includedir="c:/env-msvc-x64/include/boost-1_49" > config.py + echo boost_libdir="c:/env-msvc-x64/lib" >> config.py + scons.bat debug=no SWIFTEN_INSTALLDIR=C:\env-msvc-x64 force_configure=1 + scons.bat debug=no SWIFTEN_INSTALLDIR=C:\env-msvc-x64 C:\env-msvc-x64 + +3. unpack and compile protobuf as described in its documentation. + +Run extract_includes.bat in vsprojects/ directory and move resulting vsprojects/include/google/ directory to our C:\env-msvc-x64\include + +Move protoc.exe to C:\env-msvc-x64\bin\ and libprotobuf.lib to C:\env-msvc-x64\lib + +4. Install gtkmm + +Download installer from https://live.gnome.org/gtkmm/MSWindows and install gtkmm into C:\env-msvc-x64\ + +5. Install libpurple headers + +Download http://www.pidgin.im/download/source/ , extract it and copy libpurple directory in C:\env-msvc-x64\include + +6. You're ready! :) Clone libtransport into C:\env-msvc-x64\libtransport (You *must* clone it into this directory, because libtransport will try to find the dependencies in ../lib and ../include) + +Compile it as: + + set CMAKE_INCLUDE_PATH=C:\env-msvc-x64\include + cmake . -G "NMake Makefiles" -DBOOST_INCLUDEDIR=../include/boost-1_49 -DBOOST_LIBRARYDIR=../lib -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=C:\env-msvc-x64 -DGIT_EXECUTABLE="c:\Program Files (x86)\git\bin\git.exe" + nmake diff --git a/backends/frotz/CMakeLists.txt b/backends/frotz/CMakeLists.txt index f9bc283a486238d14b2ceef2e4c4c1e0aac2e29f..b4a033144e4435b846a6be2eb991a66a4836f596 100644 --- a/backends/frotz/CMakeLists.txt +++ b/backends/frotz/CMakeLists.txt @@ -1,12 +1,12 @@ -cmake_minimum_required(VERSION 2.6) - -ADD_SUBDIRECTORY(dfrotz) - -FILE(GLOB SRC *.c *.cpp) - -ADD_EXECUTABLE(spectrum2_frotz_backend ${SRC}) - -target_link_libraries(spectrum2_frotz_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) - -INSTALL(TARGETS spectrum2_frotz_backend RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) + +ADD_SUBDIRECTORY(dfrotz) + +FILE(GLOB SRC *.c *.cpp) + +ADD_EXECUTABLE(spectrum2_frotz_backend ${SRC}) + +target_link_libraries(spectrum2_frotz_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) + +INSTALL(TARGETS spectrum2_frotz_backend RUNTIME DESTINATION bin) + diff --git a/backends/frotz/dfrotz/CMakeLists.txt b/backends/frotz/dfrotz/CMakeLists.txt index 3c1b722a6ba87755a15ae895d10eca9205f9e3da..925e8c0a406afaf6eac31fa51a434f506ce99b3c 100644 --- a/backends/frotz/dfrotz/CMakeLists.txt +++ b/backends/frotz/dfrotz/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required(VERSION 2.6) -FILE(GLOB SRC common/*.c dumb/*.c) - -ADD_EXECUTABLE(dfrotz ${SRC}) - -# target_link_libraries(dfrotz) - -INSTALL(TARGETS dfrotz RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC common/*.c dumb/*.c) + +ADD_EXECUTABLE(dfrotz ${SRC}) + +# target_link_libraries(dfrotz) + +INSTALL(TARGETS dfrotz RUNTIME DESTINATION bin) + diff --git a/backends/libcommuni/CMakeLists.txt b/backends/libcommuni/CMakeLists.txt index 9594867c200edbaaa64f402e71b021b2da52a9e2..544f9162a0662a21ba450c6a1476bcfdf972e8f9 100644 --- a/backends/libcommuni/CMakeLists.txt +++ b/backends/libcommuni/CMakeLists.txt @@ -1,13 +1,13 @@ -cmake_minimum_required(VERSION 2.6) -FILE(GLOB SRC *.cpp) -FILE(GLOB HEADERS *.h) -QT4_WRAP_CPP(SRC ${HEADERS} OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) -ADD_EXECUTABLE(spectrum2_libcommuni_backend ${SRC}) - -if (NOT WIN32) - target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport pthread) -else () - target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport) -endif() -INSTALL(TARGETS spectrum2_libcommuni_backend RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC *.cpp) +FILE(GLOB HEADERS *.h) +QT4_WRAP_CPP(SRC ${HEADERS} OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) +ADD_EXECUTABLE(spectrum2_libcommuni_backend ${SRC}) + +if (NOT WIN32) + target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport pthread) +else () + target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport) +endif() +INSTALL(TARGETS spectrum2_libcommuni_backend RUNTIME DESTINATION bin) + diff --git a/backends/libpurple/CMakeLists.txt b/backends/libpurple/CMakeLists.txt index c03795dec1668bf2d871d596610d4fde92b00267..f31b1a720caba0a6eed5d58c2022cd137303151d 100644 --- a/backends/libpurple/CMakeLists.txt +++ b/backends/libpurple/CMakeLists.txt @@ -1,17 +1,17 @@ -cmake_minimum_required(VERSION 2.6) -FILE(GLOB SRC *.cpp) - -ADD_EXECUTABLE(spectrum2_libpurple_backend ${SRC}) - -if(CMAKE_COMPILER_IS_GNUCXX) - if (NOT WIN32) - target_link_libraries(spectrum2_libpurple_backend ${PURPLE_LIBRARY} ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport-plugin pthread) - else() - target_link_libraries(spectrum2_libpurple_backend ${PURPLE_LIBRARY} ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport-plugin) - endif() -else() -target_link_libraries(spectrum2_libpurple_backend sqlite3 ${PURPLE_LIBRARY} ${GLIB2_LIBRARIES} ${LIBXML2_LIBRARIES} ${EVENT_LIBRARIES} transport-plugin ${PROTOBUF_LIBRARY}) -endif() - -INSTALL(TARGETS spectrum2_libpurple_backend RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(spectrum2_libpurple_backend ${SRC}) + +if(CMAKE_COMPILER_IS_GNUCXX) + if (NOT WIN32) + target_link_libraries(spectrum2_libpurple_backend ${PURPLE_LIBRARY} ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport-plugin pthread) + else() + target_link_libraries(spectrum2_libpurple_backend ${PURPLE_LIBRARY} ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport-plugin) + endif() +else() +target_link_libraries(spectrum2_libpurple_backend sqlite3 ${PURPLE_LIBRARY} ${GLIB2_LIBRARIES} ${LIBXML2_LIBRARIES} ${EVENT_LIBRARIES} transport-plugin ${PROTOBUF_LIBRARY}) +endif() + +INSTALL(TARGETS spectrum2_libpurple_backend RUNTIME DESTINATION bin) + diff --git a/backends/libyahoo2/CMakeLists.txt b/backends/libyahoo2/CMakeLists.txt index 70ffe5dc7aa0d5b25eb9afa98fad449c6faff543..9a5694615f024dd8232d59f1827410a8cb4c4146 100644 --- a/backends/libyahoo2/CMakeLists.txt +++ b/backends/libyahoo2/CMakeLists.txt @@ -1,14 +1,14 @@ -cmake_minimum_required(VERSION 2.6) - -FILE(GLOB_RECURSE SRC *.c *.cpp) - -ADD_DEFINITIONS(-DHAVE_STDINT_H=1) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/yahoo) - -ADD_EXECUTABLE(spectrum2_libyahoo2_backend ${SRC}) - -target_link_libraries(spectrum2_libyahoo2_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) - -INSTALL(TARGETS spectrum2_libyahoo2_backend RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB_RECURSE SRC *.c *.cpp) + +ADD_DEFINITIONS(-DHAVE_STDINT_H=1) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/yahoo) + +ADD_EXECUTABLE(spectrum2_libyahoo2_backend ${SRC}) + +target_link_libraries(spectrum2_libyahoo2_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) + +INSTALL(TARGETS spectrum2_libyahoo2_backend RUNTIME DESTINATION bin) + diff --git a/backends/skype/CMakeLists.txt b/backends/skype/CMakeLists.txt index d27b4296aec27bac8a89fee7f4941966919884ed..c9d70510518440b5558a0f3ca3af7947980f82e9 100644 --- a/backends/skype/CMakeLists.txt +++ b/backends/skype/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required(VERSION 2.6) -FILE(GLOB SRC *.cpp) - -ADD_EXECUTABLE(spectrum2_skype_backend ${SRC}) - -target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES}) - -INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(spectrum2_skype_backend ${SRC}) + +target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES}) + +INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin) + diff --git a/backends/smstools3/CMakeLists.txt b/backends/smstools3/CMakeLists.txt index a557e243ab522862b4c467bd2f177df60992eb03..84f3497888ea40b84e601141147fe6c79abfe6a0 100644 --- a/backends/smstools3/CMakeLists.txt +++ b/backends/smstools3/CMakeLists.txt @@ -1,10 +1,10 @@ -cmake_minimum_required(VERSION 2.6) - -FILE(GLOB SRC *.c *.cpp) - -ADD_EXECUTABLE(spectrum2_smstools3_backend ${SRC}) - -target_link_libraries(spectrum2_smstools3_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) - -INSTALL(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB SRC *.c *.cpp) + +ADD_EXECUTABLE(spectrum2_smstools3_backend ${SRC}) + +target_link_libraries(spectrum2_smstools3_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) + +INSTALL(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION bin) + diff --git a/backends/swiften/CMakeLists.txt b/backends/swiften/CMakeLists.txt index b605a9478b281ff16fcde7abef7ba6557ada1e05..f90e77ef6d53b98621337c2ccee5921e5648dcb6 100644 --- a/backends/swiften/CMakeLists.txt +++ b/backends/swiften/CMakeLists.txt @@ -1,14 +1,14 @@ -cmake_minimum_required(VERSION 2.6) - -FILE(GLOB SRC *.cpp) - -ADD_EXECUTABLE(spectrum2_swiften_backend ${SRC}) - -IF (NOT WIN32) -target_link_libraries(spectrum2_swiften_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) -else() -target_link_libraries(spectrum2_swiften_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) -endif() - -INSTALL(TARGETS spectrum2_swiften_backend RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(spectrum2_swiften_backend ${SRC}) + +IF (NOT WIN32) +target_link_libraries(spectrum2_swiften_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +else() +target_link_libraries(spectrum2_swiften_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +endif() + +INSTALL(TARGETS spectrum2_swiften_backend RUNTIME DESTINATION bin) + diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index ae1094b7b9e8263158989048d84cf117195cbda2..8ed12331503d38d9f8e2b83cb72e8e732e1c9138 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -1,455 +1,455 @@ -// Transport includes -#include "transport/config.h" -#include "transport/networkplugin.h" -#include "transport/logging.h" - -#include "boost/date_time/posix_time/posix_time.hpp" - -// Swiften -#include "Swiften/Swiften.h" -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - -#ifndef WIN32 -// for signal handler -#include "unistd.h" -#include "signal.h" -#include "sys/wait.h" -#include "sys/signal.h" -#endif - -#ifndef __FreeBSD__ -#ifndef __MACH__ -// malloc_trim -#include "malloc.h" -#endif -#endif - -// Boost -#include -using namespace boost::filesystem; -using namespace boost::program_options; -using namespace Transport; - -DEFINE_LOGGER(logger, "Swiften"); -DEFINE_LOGGER(logger_xml, "backend.xml"); - -// eventloop -Swift::SimpleEventLoop *loop_; - -// Plugins -class SwiftenPlugin; -NetworkPlugin *np = NULL; -Swift::XMPPSerializer *serializer; - -class ForwardIQHandler : public Swift::IQHandler { - public: - std::map m_id2resource; - - ForwardIQHandler(NetworkPlugin *np, const std::string &user) { - m_np = np; - m_user = user; - } - - bool handleIQ(boost::shared_ptr iq) { - if (iq->getPayload() != NULL) { - return false; - } - if (iq->getType() == Swift::IQ::Get) { - m_id2resource[iq->getID()] = iq->getFrom().getResource(); - } - - iq->setTo(m_user); - std::string xml = safeByteArrayToString(serializer->serializeElement(iq)); - m_np->sendRawXML(xml); - return true; - } - - private: - NetworkPlugin *m_np; - std::string m_user; - -}; - -class SwiftenPlugin : public NetworkPlugin, Swift::XMPPParserClient { - public: - Swift::BoostNetworkFactories *m_factories; - Swift::BoostIOServiceThread m_boostIOServiceThread; - boost::shared_ptr m_conn; - bool m_firstPing; - - Swift::FullPayloadSerializerCollection collection; - Swift::XMPPParser *m_xmppParser; - Swift::FullPayloadParserFactoryCollection m_collection2; - - SwiftenPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { - this->config = config; - m_firstPing = true; - m_factories = new Swift::BoostNetworkFactories(loop); - m_conn = m_factories->getConnectionFactory()->createConnection(); - m_conn->onDataRead.connect(boost::bind(&SwiftenPlugin::_handleDataRead, this, _1)); - m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); -#if HAVE_SWIFTEN_3 - serializer = new Swift::XMPPSerializer(&collection, Swift::ClientStreamType, false); -#else - serializer = new Swift::XMPPSerializer(&collection, Swift::ClientStreamType); -#endif - m_xmppParser = new Swift::XMPPParser(this, &m_collection2, m_factories->getXMLParserFactory()); - m_xmppParser->parse(""); - - LOG4CXX_INFO(logger, "Starting the plugin."); - } - - // NetworkPlugin uses this method to send the data to networkplugin server - void sendData(const std::string &string) { - m_conn->write(Swift::createSafeByteArray(string)); - } - - // This method has to call handleDataRead with all received data from network plugin server - void _handleDataRead(boost::shared_ptr data) { - if (m_firstPing) { - m_firstPing = false; - NetworkPlugin::PluginConfig cfg; - cfg.setRawXML(true); - sendConfig(cfg); - } - std::string d(data->begin(), data->end()); - handleDataRead(d); - } - - void handleStreamStart(const Swift::ProtocolHeader&) {} -#if HAVE_SWIFTEN_3 - void handleElement(boost::shared_ptr element) { -#else - void handleElement(boost::shared_ptr element) { -#endif - boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); - if (!stanza) { - return; - } - - std::string user = stanza->getFrom().toBare(); - - boost::shared_ptr client = m_users[user]; - if (!client) - return; - - stanza->setFrom(client->getJID()); - - boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); - if (message) { - client->sendMessage(message); - return; - } - - boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); - if (presence) { - client->sendPresence(presence); - return; - } - - boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); - if (iq) { - if (m_handlers[user]->m_id2resource.find(stanza->getID()) != m_handlers[user]->m_id2resource.end()) { - std::string resource = m_handlers[user]->m_id2resource[stanza->getID()]; - if (resource.empty()) { - iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain())); - } else { - iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain(), resource)); - } - - m_handlers[user]->m_id2resource.erase(stanza->getID()); - } - client->getIQRouter()->sendIQ(iq); - return; - } - } - - void handleStreamEnd() {} - - void handleRawXML(const std::string &xml) { - m_xmppParser->parse(xml); - } - - void handleSwiftDisconnected(const std::string &user, const boost::optional &error) { - std::string message = ""; - bool reconnect = false; - if (error) { - switch(error->getType()) { - case Swift::ClientError::UnknownError: message = ("Unknown Error"); reconnect = true; break; - case Swift::ClientError::DomainNameResolveError: message = ("Unable to find server"); break; - case Swift::ClientError::ConnectionError: message = ("Error connecting to server"); break; - case Swift::ClientError::ConnectionReadError: message = ("Error while receiving server data"); reconnect = true; break; - case Swift::ClientError::ConnectionWriteError: message = ("Error while sending data to the server"); reconnect = true; break; - case Swift::ClientError::XMLError: message = ("Error parsing server data"); reconnect = true; break; - case Swift::ClientError::AuthenticationFailedError: message = ("Login/password invalid"); break; - case Swift::ClientError::CompressionFailedError: message = ("Error while compressing stream"); break; - case Swift::ClientError::ServerVerificationFailedError: message = ("Server verification failed"); break; - case Swift::ClientError::NoSupportedAuthMechanismsError: message = ("Authentication mechanisms not supported"); break; - case Swift::ClientError::UnexpectedElementError: message = ("Unexpected response"); break; - case Swift::ClientError::ResourceBindError: message = ("Error binding resource"); break; - case Swift::ClientError::SessionStartError: message = ("Error starting session"); break; - case Swift::ClientError::StreamError: message = ("Stream error"); break; - case Swift::ClientError::TLSError: message = ("Encryption error"); break; - case Swift::ClientError::ClientCertificateLoadError: message = ("Error loading certificate (Invalid password?)"); break; - case Swift::ClientError::ClientCertificateError: message = ("Certificate not authorized"); break; - - case Swift::ClientError::UnknownCertificateError: message = ("Unknown certificate"); break; - case Swift::ClientError::CertificateExpiredError: message = ("Certificate has expired"); break; - case Swift::ClientError::CertificateNotYetValidError: message = ("Certificate is not yet valid"); break; - case Swift::ClientError::CertificateSelfSignedError: message = ("Certificate is self-signed"); break; - case Swift::ClientError::CertificateRejectedError: message = ("Certificate has been rejected"); break; - case Swift::ClientError::CertificateUntrustedError: message = ("Certificate is not trusted"); break; - case Swift::ClientError::InvalidCertificatePurposeError: message = ("Certificate cannot be used for encrypting your connection"); break; - case Swift::ClientError::CertificatePathLengthExceededError: message = ("Certificate path length constraint exceeded"); break; - case Swift::ClientError::InvalidCertificateSignatureError: message = ("Invalid certificate signature"); break; - case Swift::ClientError::InvalidCAError: message = ("Invalid Certificate Authority"); break; - case Swift::ClientError::InvalidServerIdentityError: message = ("Certificate does not match the host identity"); break; - } - } - LOG4CXX_INFO(logger, user << ": Disconnected " << message); - handleDisconnected(user, reconnect ? 0 : 3, message); - - boost::shared_ptr client = m_users[user]; - if (client) { - client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); - client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); - client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); - m_users.erase(user); - m_handlers.erase(user); - } - -#ifndef WIN32 -#ifndef __FreeBSD__ -#ifndef __MACH__ - // force returning of memory chunks allocated by libxml2 to kernel - malloc_trim(0); -#endif -#endif -#endif - } - - void handleSwiftConnected(const std::string &user) { - LOG4CXX_INFO(logger, user << ": Connected to XMPP server."); - handleConnected(user); - m_users[user]->requestRoster(); - Swift::Presence::ref response = Swift::Presence::create(); - response->setFrom(m_users[user]->getJID()); - m_users[user]->sendPresence(response); - } - - void handleSwiftRosterReceived(const std::string &user) { - Swift::PresenceOracle *oracle = m_users[user]->getPresenceOracle(); - BOOST_FOREACH(const Swift::XMPPRosterItem &item, m_users[user]->getRoster()->getItems()) { - Swift::Presence::ref lastPresence = oracle->getLastPresence(item.getJID()); - pbnetwork::StatusType status = lastPresence ? ((pbnetwork::StatusType) lastPresence->getShow()) : pbnetwork::STATUS_NONE; - handleBuddyChanged(user, item.getJID().toBare().toString(), - item.getName(), item.getGroups(), status); - } - } - - void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) { -// boost::shared_ptr client = m_users[user]; -// if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) { -// return; -// } -// -// if (presence->getPayload() != NULL || presence->getPayload() != NULL) { -// return; -// } -// -// LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed"); -// -// std::string message = presence->getStatus(); -// std::string photo = ""; -// -// boost::shared_ptr update = presence->getPayload(); -// if (update) { -// photo = update->getPhotoHash(); -// } -// -// boost::optional item = m_users[user]->getRoster()->getItem(presence->getFrom()); -// if (item) { -// handleBuddyChanged(user, presence->getFrom().toBare().toString(), item->getName(), item->getGroups(), (pbnetwork::StatusType) presence->getShow(), message, photo); -// } -// else { -// std::vector groups; -// handleBuddyChanged(user, presence->getFrom().toBare().toString(), presence->getFrom().toBare(), groups, (pbnetwork::StatusType) presence->getShow(), message, photo); -// } - presence->setTo(user); - std::string xml = safeByteArrayToString(serializer->serializeElement(presence)); - sendRawXML(xml); - } - - void handleSwiftMessageReceived(const std::string &user, Swift::Message::ref message) { - message->setTo(user); - std::string xml = safeByteArrayToString(serializer->serializeElement(message)); - sendRawXML(xml); - } - - void handleSwiftenDataRead(const Swift::SafeByteArray &data) { - std::string d = safeByteArrayToString(data); - if (!boost::starts_with(d, " client = boost::make_shared(Swift::JID(legacyName + "/Spectrum"), password, m_factories); - m_users[user] = client; - client->setAlwaysTrustCertificates(); - client->onConnected.connect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); - client->onDisconnected.connect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); - client->onMessageReceived.connect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); - client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); - client->getPresenceOracle()->onPresenceChange.connect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); - client->onDataRead.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataRead, this, _1)); - client->onDataWritten.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataWritten, this, _1)); - client->getSubscriptionManager()->onPresenceSubscriptionRequest.connect(boost::bind(&SwiftenPlugin::handleSubscriptionRequest, this, user, _1, _2, _3)); - client->getSubscriptionManager()->onPresenceSubscriptionRevoked.connect(boost::bind(&SwiftenPlugin::handleSubscriptionRevoked, this, user, _1, _2)); - Swift::ClientOptions opt; - opt.allowPLAINWithoutTLS = true; - client->connect(opt); - - boost::shared_ptr handler = boost::make_shared(this, user); - client->getIQRouter()->addHandler(handler); - m_handlers[user] = handler; - } - - void handleSubscriptionRequest(const std::string &user, const Swift::JID& jid, const std::string& message, Swift::Presence::ref presence) { - handleSwiftPresenceChanged(user, presence); - } - - void handleSubscriptionRevoked(const std::string &user, const Swift::JID& jid, const std::string& message) { - Swift::Presence::ref presence = Swift::Presence::create(); - presence->setTo(user); - presence->setFrom(jid); - presence->setType(Swift::Presence::Unsubscribe); - handleSwiftPresenceChanged(user, presence); - } - - void handleLogoutRequest(const std::string &user, const std::string &legacyName) { - boost::shared_ptr client = m_users[user]; - if (client) { - client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); -// client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); - client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); - client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); - client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); - client->disconnect(); - } - } - - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") { - } - - void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) { - } - - void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { - boost::shared_ptr client = m_users[user]; - if (client) { - LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << "."); - if (!client->getRoster()->containsJID(buddyName) || client->getRoster()->getSubscriptionStateForJID(buddyName) != Swift::RosterItemPayload::Both) { - Swift::RosterItemPayload item; - item.setName(alias); - item.setJID(buddyName); - item.setGroups(groups); - boost::shared_ptr roster(new Swift::RosterPayload()); - roster->addItem(item); - Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); -// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); - request->send(); - client->getSubscriptionManager()->requestSubscription(buddyName); - } - else { - Swift::JID contact(buddyName); - Swift::RosterItemPayload item(contact, alias, client->getRoster()->getSubscriptionStateForJID(contact)); - item.setGroups(groups); - boost::shared_ptr roster(new Swift::RosterPayload()); - roster->addItem(item); - Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); -// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); - request->send(); - } - - } - } - - void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { - boost::shared_ptr client = m_users[user]; - if (client) { - Swift::RosterItemPayload item(buddyName, "", Swift::RosterItemPayload::Remove); - boost::shared_ptr roster(new Swift::RosterPayload()); - roster->addItem(item); - Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); -// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); - request->send(); - } - } - - void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { - - } - - void handleLeaveRoomRequest(const std::string &user, const std::string &room) { - - } - - private: - Config *config; - std::map > m_users; - std::map > m_handlers; -}; - -#ifndef WIN32 -static void spectrum_sigchld_handler(int sig) -{ - int status; - pid_t pid; - - do { - pid = waitpid(-1, &status, WNOHANG); - } while (pid != 0 && pid != (pid_t)-1); - - if ((pid == (pid_t) - 1) && (errno != ECHILD)) { - char errmsg[BUFSIZ]; - snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); - perror(errmsg); - } -} -#endif - - -int main (int argc, char* argv[]) { - std::string host; - int port; - -#ifndef WIN32 - if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { - std::cout << "SIGCHLD handler can't be set\n"; - return -1; - } -#endif - - std::string error; - Config *cfg = Config::createFromArgs(argc, argv, error, host, port); - if (cfg == NULL) { - std::cerr << error; - return 1; - } - - Logging::initBackendLogging(cfg); - - Swift::SimpleEventLoop eventLoop; - loop_ = &eventLoop; - np = new SwiftenPlugin(cfg, &eventLoop, host, port); - loop_->run(); - - return 0; -} +// Transport includes +#include "transport/config.h" +#include "transport/networkplugin.h" +#include "transport/logging.h" + +#include "boost/date_time/posix_time/posix_time.hpp" + +// Swiften +#include "Swiften/Swiften.h" +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + +#ifndef WIN32 +// for signal handler +#include "unistd.h" +#include "signal.h" +#include "sys/wait.h" +#include "sys/signal.h" +#endif + +#ifndef __FreeBSD__ +#ifndef __MACH__ +// malloc_trim +#include "malloc.h" +#endif +#endif + +// Boost +#include +using namespace boost::filesystem; +using namespace boost::program_options; +using namespace Transport; + +DEFINE_LOGGER(logger, "Swiften"); +DEFINE_LOGGER(logger_xml, "backend.xml"); + +// eventloop +Swift::SimpleEventLoop *loop_; + +// Plugins +class SwiftenPlugin; +NetworkPlugin *np = NULL; +Swift::XMPPSerializer *serializer; + +class ForwardIQHandler : public Swift::IQHandler { + public: + std::map m_id2resource; + + ForwardIQHandler(NetworkPlugin *np, const std::string &user) { + m_np = np; + m_user = user; + } + + bool handleIQ(boost::shared_ptr iq) { + if (iq->getPayload() != NULL) { + return false; + } + if (iq->getType() == Swift::IQ::Get) { + m_id2resource[iq->getID()] = iq->getFrom().getResource(); + } + + iq->setTo(m_user); + std::string xml = safeByteArrayToString(serializer->serializeElement(iq)); + m_np->sendRawXML(xml); + return true; + } + + private: + NetworkPlugin *m_np; + std::string m_user; + +}; + +class SwiftenPlugin : public NetworkPlugin, Swift::XMPPParserClient { + public: + Swift::BoostNetworkFactories *m_factories; + Swift::BoostIOServiceThread m_boostIOServiceThread; + boost::shared_ptr m_conn; + bool m_firstPing; + + Swift::FullPayloadSerializerCollection collection; + Swift::XMPPParser *m_xmppParser; + Swift::FullPayloadParserFactoryCollection m_collection2; + + SwiftenPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { + this->config = config; + m_firstPing = true; + m_factories = new Swift::BoostNetworkFactories(loop); + m_conn = m_factories->getConnectionFactory()->createConnection(); + m_conn->onDataRead.connect(boost::bind(&SwiftenPlugin::_handleDataRead, this, _1)); + m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); +#if HAVE_SWIFTEN_3 + serializer = new Swift::XMPPSerializer(&collection, Swift::ClientStreamType, false); +#else + serializer = new Swift::XMPPSerializer(&collection, Swift::ClientStreamType); +#endif + m_xmppParser = new Swift::XMPPParser(this, &m_collection2, m_factories->getXMLParserFactory()); + m_xmppParser->parse(""); + + LOG4CXX_INFO(logger, "Starting the plugin."); + } + + // NetworkPlugin uses this method to send the data to networkplugin server + void sendData(const std::string &string) { + m_conn->write(Swift::createSafeByteArray(string)); + } + + // This method has to call handleDataRead with all received data from network plugin server + void _handleDataRead(boost::shared_ptr data) { + if (m_firstPing) { + m_firstPing = false; + NetworkPlugin::PluginConfig cfg; + cfg.setRawXML(true); + sendConfig(cfg); + } + std::string d(data->begin(), data->end()); + handleDataRead(d); + } + + void handleStreamStart(const Swift::ProtocolHeader&) {} +#if HAVE_SWIFTEN_3 + void handleElement(boost::shared_ptr element) { +#else + void handleElement(boost::shared_ptr element) { +#endif + boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); + if (!stanza) { + return; + } + + std::string user = stanza->getFrom().toBare(); + + boost::shared_ptr client = m_users[user]; + if (!client) + return; + + stanza->setFrom(client->getJID()); + + boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); + if (message) { + client->sendMessage(message); + return; + } + + boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); + if (presence) { + client->sendPresence(presence); + return; + } + + boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); + if (iq) { + if (m_handlers[user]->m_id2resource.find(stanza->getID()) != m_handlers[user]->m_id2resource.end()) { + std::string resource = m_handlers[user]->m_id2resource[stanza->getID()]; + if (resource.empty()) { + iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain())); + } else { + iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain(), resource)); + } + + m_handlers[user]->m_id2resource.erase(stanza->getID()); + } + client->getIQRouter()->sendIQ(iq); + return; + } + } + + void handleStreamEnd() {} + + void handleRawXML(const std::string &xml) { + m_xmppParser->parse(xml); + } + + void handleSwiftDisconnected(const std::string &user, const boost::optional &error) { + std::string message = ""; + bool reconnect = false; + if (error) { + switch(error->getType()) { + case Swift::ClientError::UnknownError: message = ("Unknown Error"); reconnect = true; break; + case Swift::ClientError::DomainNameResolveError: message = ("Unable to find server"); break; + case Swift::ClientError::ConnectionError: message = ("Error connecting to server"); break; + case Swift::ClientError::ConnectionReadError: message = ("Error while receiving server data"); reconnect = true; break; + case Swift::ClientError::ConnectionWriteError: message = ("Error while sending data to the server"); reconnect = true; break; + case Swift::ClientError::XMLError: message = ("Error parsing server data"); reconnect = true; break; + case Swift::ClientError::AuthenticationFailedError: message = ("Login/password invalid"); break; + case Swift::ClientError::CompressionFailedError: message = ("Error while compressing stream"); break; + case Swift::ClientError::ServerVerificationFailedError: message = ("Server verification failed"); break; + case Swift::ClientError::NoSupportedAuthMechanismsError: message = ("Authentication mechanisms not supported"); break; + case Swift::ClientError::UnexpectedElementError: message = ("Unexpected response"); break; + case Swift::ClientError::ResourceBindError: message = ("Error binding resource"); break; + case Swift::ClientError::SessionStartError: message = ("Error starting session"); break; + case Swift::ClientError::StreamError: message = ("Stream error"); break; + case Swift::ClientError::TLSError: message = ("Encryption error"); break; + case Swift::ClientError::ClientCertificateLoadError: message = ("Error loading certificate (Invalid password?)"); break; + case Swift::ClientError::ClientCertificateError: message = ("Certificate not authorized"); break; + + case Swift::ClientError::UnknownCertificateError: message = ("Unknown certificate"); break; + case Swift::ClientError::CertificateExpiredError: message = ("Certificate has expired"); break; + case Swift::ClientError::CertificateNotYetValidError: message = ("Certificate is not yet valid"); break; + case Swift::ClientError::CertificateSelfSignedError: message = ("Certificate is self-signed"); break; + case Swift::ClientError::CertificateRejectedError: message = ("Certificate has been rejected"); break; + case Swift::ClientError::CertificateUntrustedError: message = ("Certificate is not trusted"); break; + case Swift::ClientError::InvalidCertificatePurposeError: message = ("Certificate cannot be used for encrypting your connection"); break; + case Swift::ClientError::CertificatePathLengthExceededError: message = ("Certificate path length constraint exceeded"); break; + case Swift::ClientError::InvalidCertificateSignatureError: message = ("Invalid certificate signature"); break; + case Swift::ClientError::InvalidCAError: message = ("Invalid Certificate Authority"); break; + case Swift::ClientError::InvalidServerIdentityError: message = ("Certificate does not match the host identity"); break; + } + } + LOG4CXX_INFO(logger, user << ": Disconnected " << message); + handleDisconnected(user, reconnect ? 0 : 3, message); + + boost::shared_ptr client = m_users[user]; + if (client) { + client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); + client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + m_users.erase(user); + m_handlers.erase(user); + } + +#ifndef WIN32 +#ifndef __FreeBSD__ +#ifndef __MACH__ + // force returning of memory chunks allocated by libxml2 to kernel + malloc_trim(0); +#endif +#endif +#endif + } + + void handleSwiftConnected(const std::string &user) { + LOG4CXX_INFO(logger, user << ": Connected to XMPP server."); + handleConnected(user); + m_users[user]->requestRoster(); + Swift::Presence::ref response = Swift::Presence::create(); + response->setFrom(m_users[user]->getJID()); + m_users[user]->sendPresence(response); + } + + void handleSwiftRosterReceived(const std::string &user) { + Swift::PresenceOracle *oracle = m_users[user]->getPresenceOracle(); + BOOST_FOREACH(const Swift::XMPPRosterItem &item, m_users[user]->getRoster()->getItems()) { + Swift::Presence::ref lastPresence = oracle->getLastPresence(item.getJID()); + pbnetwork::StatusType status = lastPresence ? ((pbnetwork::StatusType) lastPresence->getShow()) : pbnetwork::STATUS_NONE; + handleBuddyChanged(user, item.getJID().toBare().toString(), + item.getName(), item.getGroups(), status); + } + } + + void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) { +// boost::shared_ptr client = m_users[user]; +// if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) { +// return; +// } +// +// if (presence->getPayload() != NULL || presence->getPayload() != NULL) { +// return; +// } +// +// LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed"); +// +// std::string message = presence->getStatus(); +// std::string photo = ""; +// +// boost::shared_ptr update = presence->getPayload(); +// if (update) { +// photo = update->getPhotoHash(); +// } +// +// boost::optional item = m_users[user]->getRoster()->getItem(presence->getFrom()); +// if (item) { +// handleBuddyChanged(user, presence->getFrom().toBare().toString(), item->getName(), item->getGroups(), (pbnetwork::StatusType) presence->getShow(), message, photo); +// } +// else { +// std::vector groups; +// handleBuddyChanged(user, presence->getFrom().toBare().toString(), presence->getFrom().toBare(), groups, (pbnetwork::StatusType) presence->getShow(), message, photo); +// } + presence->setTo(user); + std::string xml = safeByteArrayToString(serializer->serializeElement(presence)); + sendRawXML(xml); + } + + void handleSwiftMessageReceived(const std::string &user, Swift::Message::ref message) { + message->setTo(user); + std::string xml = safeByteArrayToString(serializer->serializeElement(message)); + sendRawXML(xml); + } + + void handleSwiftenDataRead(const Swift::SafeByteArray &data) { + std::string d = safeByteArrayToString(data); + if (!boost::starts_with(d, " client = boost::make_shared(Swift::JID(legacyName + "/Spectrum"), password, m_factories); + m_users[user] = client; + client->setAlwaysTrustCertificates(); + client->onConnected.connect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); + client->onDisconnected.connect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.connect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); + client->getPresenceOracle()->onPresenceChange.connect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); + client->onDataRead.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataRead, this, _1)); + client->onDataWritten.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataWritten, this, _1)); + client->getSubscriptionManager()->onPresenceSubscriptionRequest.connect(boost::bind(&SwiftenPlugin::handleSubscriptionRequest, this, user, _1, _2, _3)); + client->getSubscriptionManager()->onPresenceSubscriptionRevoked.connect(boost::bind(&SwiftenPlugin::handleSubscriptionRevoked, this, user, _1, _2)); + Swift::ClientOptions opt; + opt.allowPLAINWithoutTLS = true; + client->connect(opt); + + boost::shared_ptr handler = boost::make_shared(this, user); + client->getIQRouter()->addHandler(handler); + m_handlers[user] = handler; + } + + void handleSubscriptionRequest(const std::string &user, const Swift::JID& jid, const std::string& message, Swift::Presence::ref presence) { + handleSwiftPresenceChanged(user, presence); + } + + void handleSubscriptionRevoked(const std::string &user, const Swift::JID& jid, const std::string& message) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setTo(user); + presence->setFrom(jid); + presence->setType(Swift::Presence::Unsubscribe); + handleSwiftPresenceChanged(user, presence); + } + + void handleLogoutRequest(const std::string &user, const std::string &legacyName) { + boost::shared_ptr client = m_users[user]; + if (client) { + client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); +// client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); + client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); + client->disconnect(); + } + } + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") { + } + + void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) { + } + + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + boost::shared_ptr client = m_users[user]; + if (client) { + LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << "."); + if (!client->getRoster()->containsJID(buddyName) || client->getRoster()->getSubscriptionStateForJID(buddyName) != Swift::RosterItemPayload::Both) { + Swift::RosterItemPayload item; + item.setName(alias); + item.setJID(buddyName); + item.setGroups(groups); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + client->getSubscriptionManager()->requestSubscription(buddyName); + } + else { + Swift::JID contact(buddyName); + Swift::RosterItemPayload item(contact, alias, client->getRoster()->getSubscriptionStateForJID(contact)); + item.setGroups(groups); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + } + + } + } + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { + boost::shared_ptr client = m_users[user]; + if (client) { + Swift::RosterItemPayload item(buddyName, "", Swift::RosterItemPayload::Remove); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + } + } + + void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { + + } + + void handleLeaveRoomRequest(const std::string &user, const std::string &room) { + + } + + private: + Config *config; + std::map > m_users; + std::map > m_handlers; +}; + +#ifndef WIN32 +static void spectrum_sigchld_handler(int sig) +{ + int status; + pid_t pid; + + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid != 0 && pid != (pid_t)-1); + + if ((pid == (pid_t) - 1) && (errno != ECHILD)) { + char errmsg[BUFSIZ]; + snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); + perror(errmsg); + } +} +#endif + + +int main (int argc, char* argv[]) { + std::string host; + int port; + +#ifndef WIN32 + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + return -1; + } +#endif + + std::string error; + Config *cfg = Config::createFromArgs(argc, argv, error, host, port); + if (cfg == NULL) { + std::cerr << error; + return 1; + } + + Logging::initBackendLogging(cfg); + + Swift::SimpleEventLoop eventLoop; + loop_ = &eventLoop; + np = new SwiftenPlugin(cfg, &eventLoop, host, port); + loop_->run(); + + return 0; +} diff --git a/backends/template/CMakeLists.txt b/backends/template/CMakeLists.txt index d0be90ca48f6a0b1e215420c16a0145ecb4c3288..6de3857e7bb419a3799ee8429129302135c36b58 100644 --- a/backends/template/CMakeLists.txt +++ b/backends/template/CMakeLists.txt @@ -1,18 +1,18 @@ -cmake_minimum_required(VERSION 2.6) - -FILE(GLOB SRC *.c *.cpp) - -ADD_EXECUTABLE(spectrum2_template_backend ${SRC}) - -if (CMAKE_COMPILER_IS_GNUCXX) -if (NOT WIN32) -target_link_libraries(spectrum2_template_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) -else() -target_link_libraries(spectrum2_template_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) -endif() -else() -target_link_libraries(spectrum2_template_backend transport ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) -endif() - -#INSTALL(TARGETS spectrum2_template_backend RUNTIME DESTINATION bin) - +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB SRC *.c *.cpp) + +ADD_EXECUTABLE(spectrum2_template_backend ${SRC}) + +if (CMAKE_COMPILER_IS_GNUCXX) +if (NOT WIN32) +target_link_libraries(spectrum2_template_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +else() +target_link_libraries(spectrum2_template_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +endif() +else() +target_link_libraries(spectrum2_template_backend transport ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +endif() + +#INSTALL(TARGETS spectrum2_template_backend RUNTIME DESTINATION bin) + diff --git a/backends/twitter/TwitterPlugin.cpp b/backends/twitter/TwitterPlugin.cpp index 543e2dbb9c72b051b60f5ceda03a20035759646e..a91d288e7e442748f4956ede6a13be0a9ed54477 100644 --- a/backends/twitter/TwitterPlugin.cpp +++ b/backends/twitter/TwitterPlugin.cpp @@ -1,894 +1,894 @@ -#include "TwitterPlugin.h" -#include "Requests/StatusUpdateRequest.h" -#include "Requests/DirectMessageRequest.h" -#include "Requests/TimelineRequest.h" -#include "Requests/FetchFriends.h" -#include "Requests/HelpMessageRequest.h" -#include "Requests/PINExchangeProcess.h" -#include "Requests/OAuthFlow.h" -#include "Requests/CreateFriendRequest.h" -#include "Requests/DestroyFriendRequest.h" -#include "Requests/RetweetRequest.h" -#include "Requests/ProfileImageRequest.h" -#include "Swiften/StringCodecs/Hexify.h" - -DEFINE_LOGGER(logger, "Twitter Backend"); - -TwitterPlugin *np = NULL; -Swift::SimpleEventLoop *loop_; // Event Loop - -const std::string OLD_APP_KEY = "PCWAdQpyyR12ezp2fVwEhw"; -const std::string OLD_APP_SECRET = "EveLmCXJIg2R7BTCpm6OWV8YyX49nI0pxnYXh7JMvDg"; - -#define abs(x) ((x)<0?-(x):(x)) -#define SHA(x) (Swift::Hexify::hexify(Swift::SHA1::getHash(Swift::createByteArray((x))))) - -//Compares two +ve intergers 'a' and 'b' represented as strings -static int cmp(std::string a, std::string b) -{ - int diff = abs((int)a.size() - (int)b.size()); - if(a.size() < b.size()) a = std::string(diff,'0') + a; - else b = std::string(diff,'0') + b; - - if(a == b) return 0; - if(a < b) return -1; - return 1; -} - - -TwitterPlugin::TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, StorageBackend *storagebackend, const std::string &host, int port) : NetworkPlugin() -{ - this->config = config; - this->storagebackend = storagebackend; - this->m_firstPing = true; - - if (CONFIG_HAS_KEY(config, "twitter.consumer_key") == false) { - consumerKey = "5mFePMiJi0KpeURONkelg"; - } - else { - consumerKey = CONFIG_STRING(config, "twitter.consumer_key"); - } - if (CONFIG_HAS_KEY(config, "twitter.consumer_secret") == false) { - consumerSecret = "YFZCDJwRhbkccXEnaYr1waCQejTJcOY8F7l5Wim3FA"; - } - else { - consumerSecret = CONFIG_STRING(config, "twitter.consumer_secret"); - } - - if (consumerSecret.empty() || consumerKey.empty()) { - LOG4CXX_ERROR(logger, "Consumer key and Consumer secret can't be empty."); - exit(1); - } - - adminLegacyName = "twitter.com"; - adminChatRoom = "#twitter"; - adminNickName = "twitter"; - adminAlias = "twitter"; - - OAUTH_KEY = "twitter_oauth_token"; - OAUTH_SECRET = "twitter_oauth_secret"; - MODE = "mode"; - - m_factories = new Swift::BoostNetworkFactories(loop); - m_conn = m_factories->getConnectionFactory()->createConnection(); - m_conn->onDataRead.connect(boost::bind(&TwitterPlugin::_handleDataRead, this, _1)); - m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); - - tp = new ThreadPool(loop_, 10); - - tweet_timer = m_factories->getTimerFactory()->createTimer(90000); - message_timer = m_factories->getTimerFactory()->createTimer(90000); - - tweet_timer->onTick.connect(boost::bind(&TwitterPlugin::pollForTweets, this)); - message_timer->onTick.connect(boost::bind(&TwitterPlugin::pollForDirectMessages, this)); - - tweet_timer->start(); - message_timer->start(); - - LOG4CXX_INFO(logger, "Starting the plugin."); -} - -TwitterPlugin::~TwitterPlugin() -{ - delete storagebackend; - std::set::iterator it; - for(it = onlineUsers.begin() ; it != onlineUsers.end() ; it++) delete userdb[*it].sessions; - delete tp; -} - -// Send data to NetworkPlugin server -void TwitterPlugin::sendData(const std::string &string) -{ - m_conn->write(Swift::createSafeByteArray(string)); -} - -// Receive date from the NetworkPlugin server and invoke the appropirate payload handler (implement in the NetworkPlugin class) -void TwitterPlugin::_handleDataRead(boost::shared_ptr data) -{ - if (m_firstPing) { - m_firstPing = false; - // Users can join the network without registering if we allow - // one user to connect multiple IRC networks. - NetworkPlugin::PluginConfig cfg; - cfg.setNeedPassword(false); - sendConfig(cfg); - } - - std::string d(data->begin(), data->end()); - handleDataRead(d); -} - -// User trying to login into his twitter account -void TwitterPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) -{ - if(userdb.count(user) && (userdb[user].connectionState == NEW || - userdb[user].connectionState == CONNECTED || - userdb[user].connectionState == WAITING_FOR_PIN)) { - LOG4CXX_INFO(logger, std::string("A session corresponding to ") + user + std::string(" is already active")) - return; - } - - LOG4CXX_INFO(logger, std::string("Received login request for ") + user) - initUserSession(user, legacyName, password); - handleConnected(user); - - LOG4CXX_INFO(logger, "SPECTRUM 1 USER? - " << (userdb[user].spectrum1User? "true" : "false")) - - LOG4CXX_INFO(logger, user << ": Adding Buddy " << adminLegacyName << " " << adminAlias) - handleBuddyChanged(user, adminLegacyName, adminAlias, std::vector(), pbnetwork::STATUS_ONLINE); - userdb[user].nickName = ""; - - LOG4CXX_INFO(logger, "Querying database for usersettings of " << user) - std::string key, secret; - getUserOAuthKeyAndSecret(user, key, secret); - - if(key == "" || secret == "") { - LOG4CXX_INFO(logger, "Intiating OAuth Flow for user " << user) - setTwitterMode(user, 0); - tp->runAsThread(new OAuthFlow(np, userdb[user].sessions, user, userdb[user].sessions->getTwitterUsername())); - } else { - LOG4CXX_INFO(logger, user << " is already registerd. Using the stored oauth key and secret") - LOG4CXX_INFO(logger, key << " " << secret) - pinExchangeComplete(user, key, secret); - } -} - -// User logging out -void TwitterPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) -{ - if (userdb.count(user)) { - delete userdb[user].sessions; - userdb[user].sessions = NULL; - userdb[user].connectionState = DISCONNECTED; - } - - if(onlineUsers.count(user)) { - onlineUsers.erase(user); - } -} - -// User joining a Chatroom -void TwitterPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) -{ - if(room == adminChatRoom) { - LOG4CXX_INFO(logger, "Received Join Twitter room request for " << user) - - setTwitterMode(user, 2); - handleParticipantChanged(user, adminNickName, room, 0, pbnetwork::STATUS_ONLINE); - userdb[user].nickName = nickname; - handleMessage(user, adminChatRoom, "Connected to Twitter room! Populating your followers list", adminNickName); - tp->runAsThread(new FetchFriends(userdb[user].sessions, user, - boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); - } else { - setTwitterMode(user, 0); - LOG4CXX_ERROR(logger, "Couldn't connect to chatroom - " << room <<"! Try twitter-chatroom as the chatroom to access Twitter account") - handleMessage(user, adminLegacyName, "Couldn't connect to chatroom! Try twitter-chatroom as the chatroom to access Twitter account"); - } -} - -// User leaving a Chatroom -void TwitterPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) -{ - if(room == adminChatRoom && onlineUsers.count(user)) { - LOG4CXX_INFO(logger, "Leaving chatroom! Switching back to default mode 0") - setTwitterMode(user, 0); - handleBuddyChanged(user, adminLegacyName, adminAlias, std::vector(), pbnetwork::STATUS_ONLINE); - } -} - -// Messages to be sent to Twitter -void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &/*id*/) -{ - - LOG4CXX_INFO(logger, "Received " << user << " --> " << legacyName << " - " << message) - - if(legacyName == adminLegacyName || legacyName == adminChatRoom) { - std::string cmd = "", data = ""; - - /** Parsing the message - Assuming message format to be [ ]***/ - int i; - for(i=0 ; irunAsThread(new PINExchangeProcess(np, userdb[user].sessions, user, data)); - else if(cmd == "#help") - tp->runAsThread(new HelpMessageRequest(user, CONFIG_STRING(config, "service.jid"), boost::bind(&TwitterPlugin::helpMessageResponse, this, _1, _2))); - else if(cmd[0] == '@') { - std::string username = cmd.substr(1); - tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, username, data, - boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); - } - else if(cmd == "#status") - tp->runAsThread(new StatusUpdateRequest(userdb[user].sessions, user, data, - boost::bind(&TwitterPlugin::statusUpdateResponse, this, _1, _2))); - else if(cmd == "#timeline") - tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, data, "", - boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); - else if(cmd == "#friends") - tp->runAsThread(new FetchFriends(userdb[user].sessions, user, - boost::bind(&TwitterPlugin::displayFriendlist, this, _1, _2, _3, _4))); - else if(cmd == "#follow") - tp->runAsThread(new CreateFriendRequest(userdb[user].sessions, user, data.substr(0,data.find('@')), - boost::bind(&TwitterPlugin::createFriendResponse, this, _1, _2, _3, _4))); - else if(cmd == "#unfollow") - tp->runAsThread(new DestroyFriendRequest(userdb[user].sessions, user, data.substr(0,data.find('@')), - boost::bind(&TwitterPlugin::deleteFriendResponse, this, _1, _2, _3))); - else if(cmd == "#retweet") - tp->runAsThread(new RetweetRequest(userdb[user].sessions, user, data, - boost::bind(&TwitterPlugin::RetweetResponse, this, _1, _2))); - else if(cmd == "#mode") { - int m = 0; - m = atoi(data.c_str()); - mode prevm = userdb[user].twitterMode; - - if((mode)m == userdb[user].twitterMode) return; //If same as current mode return - if(m < 0 || m > 2) { // Invalid modes - handleMessage(user, adminLegacyName, std::string("Error! Unknown mode ") + data + ". Allowed values 0,1,2." ); - return; - } - - setTwitterMode(user, m); - if((userdb[user].twitterMode == SINGLECONTACT || userdb[user].twitterMode == CHATROOM) && prevm == MULTIPLECONTACT) clearRoster(user); - else if(userdb[user].twitterMode == MULTIPLECONTACT) - tp->runAsThread(new FetchFriends(userdb[user].sessions, user, boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); - - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("Changed mode to ") + data, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - - LOG4CXX_INFO(logger, user << ": Changed mode to " << data << " <" << (userdb[user].twitterMode == CHATROOM ? adminNickName : "") << ">" ) - } - - else if(userdb[user].twitterMode == CHATROOM) { - std::string buddy = message.substr(0, message.find(":")); - if(userdb[user].buddies.count(buddy) == 0) { - tp->runAsThread(new StatusUpdateRequest(userdb[user].sessions, user, message, - boost::bind(&TwitterPlugin::statusUpdateResponse, this, _1, _2))); - } else { - data = message.substr(message.find(":")+1); //Can parse better??:P - tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, data, - boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); - } - } - else handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - "Unknown command! Type #help for a list of available commands.", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } - - else { - std::string buddy = legacyName; - if(userdb[user].twitterMode == CHATROOM) buddy = legacyName.substr(legacyName.find("/") + 1); - if(legacyName != "twitter") { - tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, message, - boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); - } - } -} - -void TwitterPlugin::handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) -{ - if(userdb[user].connectionState != CONNECTED) { - LOG4CXX_ERROR(logger, user << " is not connected to twitter!") - return; - } - - LOG4CXX_INFO(logger, user << " - Adding Twitter contact " << buddyName) - tp->runAsThread(new CreateFriendRequest(userdb[user].sessions, user, buddyName, - boost::bind(&TwitterPlugin::createFriendResponse, this, _1, _2, _3, _4))); -} - -void TwitterPlugin::handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) -{ - if(userdb[user].connectionState != CONNECTED) { - LOG4CXX_ERROR(logger, user << " is not connected to twitter!") - return; - } - - LOG4CXX_INFO(logger, user << " - Removing Twitter contact " << buddyName) - tp->runAsThread(new DestroyFriendRequest(userdb[user].sessions, user, buddyName, - boost::bind(&TwitterPlugin::deleteFriendResponse, this, _1, _2, _3))); -} - -void TwitterPlugin::handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) -{ - if(userdb[user].connectionState != CONNECTED) { - LOG4CXX_ERROR(logger, user << " is not connected to twitter!") - return; - } - - LOG4CXX_INFO(logger, user << " - VCardRequest for " << legacyName << ", " << userdb[user].buddiesInfo[legacyName].getProfileImgURL()) - - if(getTwitterMode(user) != SINGLECONTACT && userdb[user].buddies.count(legacyName) - && userdb[user].buddiesInfo[legacyName].getProfileImgURL().length()) { - if(userdb[user].buddiesImgs.count(legacyName) == 0) { - tp->runAsThread(new ProfileImageRequest(config, user, legacyName, userdb[user].buddiesInfo[legacyName].getProfileImgURL(), id, - boost::bind(&TwitterPlugin::profileImageResponse, this, _1, _2, _3, _4, _5))); - } - handleVCard(user, id, legacyName, legacyName, "", userdb[user].buddiesImgs[legacyName]); - } -} - -void TwitterPlugin::pollForTweets() -{ - boost::mutex::scoped_lock lock(userlock); - std::set::iterator it = onlineUsers.begin(); - while(it != onlineUsers.end()) { - std::string user = *it; - tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, "", getMostRecentTweetIDUnsafe(user), - boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); - it++; - } - tweet_timer->start(); -} - -void TwitterPlugin::pollForDirectMessages() -{ - boost::mutex::scoped_lock lock(userlock); - std::set::iterator it = onlineUsers.begin(); - while(it != onlineUsers.end()) { - std::string user = *it; - tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, "", getMostRecentDMIDUnsafe(user), - boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); - it++; - } - message_timer->start(); -} - - -bool TwitterPlugin::getUserOAuthKeyAndSecret(const std::string user, std::string &key, std::string &secret) -{ - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return false; - } - - key="", secret=""; int type; - storagebackend->getUserSetting((long)info.id, OAUTH_KEY, type, key); - storagebackend->getUserSetting((long)info.id, OAUTH_SECRET, type, secret); - return true; -} - -bool TwitterPlugin::checkSpectrum1User(const std::string user) -{ - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return false; - } - - std::string first_synchronization_done = ""; - int type; - storagebackend->getUserSetting((long)info.id, "first_synchronization_done", type, first_synchronization_done); - - LOG4CXX_INFO(logger, "first_synchronization_done: " << first_synchronization_done) - - if(first_synchronization_done.length()) return true; - return false; -} - -int TwitterPlugin::getTwitterMode(const std::string user) -{ - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return -1; - } - - int type; int m; - std::string s_m; - storagebackend->getUserSetting((long)info.id, MODE, type, s_m); - if(s_m == "") { - s_m = "0"; - storagebackend->updateUserSetting((long)info.id, MODE, s_m); - } - m = atoi(s_m.c_str()); - return m; -} - -bool TwitterPlugin::setTwitterMode(const std::string user, int m) -{ - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return false; - } - - if(m < 0 || m > 2) { - LOG4CXX_ERROR(logger, "Unknown mode " << m <<". Using default mode 0") - m = 0; - } - - userdb[user].twitterMode = (mode)m; - - //int type; - std::string s_m = std::string(1,m+'0'); - LOG4CXX_ERROR(logger, "Storing mode " << m <<" for user " << user) - storagebackend->updateUserSetting((long)info.id, MODE, s_m); - return true; -} - -bool TwitterPlugin::storeUserOAuthKeyAndSecret(const std::string user, const std::string OAuthKey, const std::string OAuthSecret) -{ - - boost::mutex::scoped_lock lock(dblock); - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return false; - } - - storagebackend->updateUserSetting((long)info.id, OAUTH_KEY, OAuthKey); - storagebackend->updateUserSetting((long)info.id, OAUTH_SECRET, OAuthSecret); - return true; -} - -void TwitterPlugin::initUserSession(const std::string user, const std::string legacyName, const std::string password) -{ - boost::mutex::scoped_lock lock(userlock); - - std::string username = legacyName; - std::string passwd = password; - LOG4CXX_INFO(logger, username + " " + passwd) - - userdb[user].sessions = new twitCurl(); - if(CONFIG_HAS_KEY(config,"proxy.server")) { - std::string ip = CONFIG_STRING(config,"proxy.server"); - - std::ostringstream out; - out << CONFIG_INT(config,"proxy.port"); - std::string port = out.str(); - - std::string puser = CONFIG_STRING(config,"proxy.user"); - std::string ppasswd = CONFIG_STRING(config,"proxy.password"); - - LOG4CXX_INFO(logger, ip << " " << port << " " << puser << " " << ppasswd) - - if(ip != "localhost" && port != "0") { - userdb[user].sessions->setProxyServerIp(ip); - userdb[user].sessions->setProxyServerPort(port); - userdb[user].sessions->setProxyUserName(puser); - userdb[user].sessions->setProxyPassword(ppasswd); - } - } - - //Check if the user is spectrum1 user - userdb[user].spectrum1User = checkSpectrum1User(user); - - userdb[user].connectionState = NEW; - userdb[user].legacyName = username; - userdb[user].sessions->setTwitterUsername(username); - userdb[user].sessions->setTwitterPassword(passwd); - - if(!userdb[user].spectrum1User) { - userdb[user].sessions->getOAuth().setConsumerKey(consumerKey); - userdb[user].sessions->getOAuth().setConsumerSecret(consumerSecret); - } else { - userdb[user].sessions->getOAuth().setConsumerKey(OLD_APP_KEY); - userdb[user].sessions->getOAuth().setConsumerSecret(OLD_APP_SECRET); - } -} - -void TwitterPlugin::OAuthFlowComplete(const std::string user, twitCurl *obj) -{ - boost::mutex::scoped_lock lock(userlock); - - delete userdb[user].sessions; - userdb[user].sessions = obj->clone(); - userdb[user].connectionState = WAITING_FOR_PIN; -} - -void TwitterPlugin::pinExchangeComplete(const std::string user, const std::string OAuthAccessTokenKey, const std::string OAuthAccessTokenSecret) -{ - boost::mutex::scoped_lock lock(userlock); - - userdb[user].sessions->getOAuth().setOAuthTokenKey( OAuthAccessTokenKey ); - userdb[user].sessions->getOAuth().setOAuthTokenSecret( OAuthAccessTokenSecret ); - userdb[user].connectionState = CONNECTED; - userdb[user].twitterMode = (mode)getTwitterMode(user); - - if(userdb[user].twitterMode == MULTIPLECONTACT) { - tp->runAsThread(new FetchFriends(userdb[user].sessions, user, boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); - } - - onlineUsers.insert(user); - userdb[user].mostRecentTweetID = ""; - userdb[user].mostRecentDirectMessageID = ""; -} - -void TwitterPlugin::updateLastTweetID(const std::string user, const std::string ID) -{ - boost::mutex::scoped_lock lock(userlock); - userdb[user].mostRecentTweetID = ID; - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return; - } - - storagebackend->updateUserSetting((long)info.id, "twitter_last_tweet", ID); -} - -std::string TwitterPlugin::getMostRecentTweetIDUnsafe(const std::string user) -{ - std::string ID = ""; - if(onlineUsers.count(user)) { - ID = userdb[user].mostRecentTweetID; - if (ID.empty()) { - int type; - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - } - else { - storagebackend->getUserSetting(info.id, "twitter_last_tweet", type, ID); - } - } - } - return ID; -} - -std::string TwitterPlugin::getMostRecentTweetID(const std::string user) -{ - boost::mutex::scoped_lock lock(userlock); - return getMostRecentTweetIDUnsafe(user); -} - -void TwitterPlugin::updateLastDMID(const std::string user, const std::string ID) -{ - boost::mutex::scoped_lock lock(userlock); - userdb[user].mostRecentDirectMessageID = ID; - - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - return; - } - - storagebackend->updateUserSetting((long)info.id, "twitter_last_dm", ID); -} - -std::string TwitterPlugin::getMostRecentDMIDUnsafe(const std::string user) { - std::string ID = ""; - if(onlineUsers.count(user)) { - ID = userdb[user].mostRecentDirectMessageID; - if (ID.empty()) { - int type; - UserInfo info; - if(storagebackend->getUser(user, info) == false) { - LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") - } - else { - storagebackend->getUserSetting(info.id, "twitter_last_dm", type, ID); - } - } - } - return ID; -} - -std::string TwitterPlugin::getMostRecentDMID(const std::string user) -{ - boost::mutex::scoped_lock lock(userlock); - return getMostRecentDMIDUnsafe(user); -} - -/************************************** Twitter response functions **********************************/ -void TwitterPlugin::statusUpdateResponse(std::string &user, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } else { - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - "Status Update successful", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } -} - -void TwitterPlugin::helpMessageResponse(std::string &user, std::string &msg) -{ - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - msg, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); -} - -void TwitterPlugin::clearRoster(const std::string user) -{ - if(userdb[user].buddies.size() == 0) return; - std::set::iterator it = userdb[user].buddies.begin(); - while(it != userdb[user].buddies.end()) { - handleBuddyRemoved(user, *it); - it++; - } - userdb[user].buddies.clear(); -} - -void TwitterPlugin::populateRoster(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg) -{ - if(errMsg.getMessage().length() == 0) - { - for(int i=0 ; i(), -#if HAVE_SWIFTEN_3 - pbnetwork::STATUS_ONLINE, lastTweet, Swift::byteArrayToString(cryptoProvider->getSHA1Hash(Swift::createByteArray(friendAvatars[i])))); -#else - pbnetwork::STATUS_ONLINE, lastTweet, SHA(friendAvatars[i])); -#endif - } - else if(userdb[user].twitterMode == CHATROOM) - handleParticipantChanged(user, friends[i].getScreenName(), adminChatRoom, 0, pbnetwork::STATUS_ONLINE); - - /*handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - friends[i].getScreenName() + " - " + friends[i].getLastStatus().getTweet(), - userdb[user].twitterMode == CHATROOM ? adminNickName : "");*/ - } - } else { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("Error populating roster - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } - - if(userdb[user].twitterMode == CHATROOM) handleParticipantChanged(user, userdb[user].nickName, adminChatRoom, 0, pbnetwork::STATUS_ONLINE); -} - -void TwitterPlugin::displayFriendlist(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg) -{ - if(errMsg.getMessage().length() == 0) - { - std::string userlist = "\n***************USER LIST****************\n"; - for(int i=0 ; i < friends.size() ; i++) { - userlist += " - " + friends[i].getUserName() + " (" + friends[i].getScreenName() + ")\n"; - } - userlist += "***************************************\n"; - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - userlist, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } else { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } - -} - -void TwitterPlugin::displayTweets(std::string &user, std::string &userRequested, std::vector &tweets , Error &errMsg) -{ - if(errMsg.getMessage().length() == 0) { - std::map lastTweet; - std::map::iterator it; - - for(int i = tweets.size() - 1 ; i >= 0 ; i--) { - if(userdb[user].twitterMode != CHATROOM) { - std::string m = " - " + tweets[i].getUserData().getScreenName() + ": " + tweets[i].getTweet() + " (MsgId: " + (tweets[i].getRetweetID().empty() ? tweets[i].getID() : tweets[i].getRetweetID()) + ")\n"; - handleMessage(user, adminLegacyName, m, "", "", tweets[i].getCreationTime(), true); - - std::string scrname = tweets[i].getUserData().getScreenName(); - if(lastTweet.count(scrname) == 0 || cmp(tweets[lastTweet[scrname]].getID(), tweets[i].getID()) <= 0) lastTweet[scrname] = i; - - } else { - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - tweets[i].getTweet() + " (MsgId: " + (tweets[i].getRetweetID().empty() ? tweets[i].getID() : tweets[i].getRetweetID()) + ")", tweets[i].getUserData().getScreenName(), "", tweets[i].getCreationTime(), true); - } - } - - if(userdb[user].twitterMode == MULTIPLECONTACT) { - //Set as status user's last tweet - for(it=lastTweet.begin() ; it!=lastTweet.end() ; it++) { - int t = it->second; - handleBuddyChanged(user, tweets[t].getUserData().getScreenName(), tweets[t].getUserData().getUserName(), - std::vector(), pbnetwork::STATUS_ONLINE, tweets[t].getTweet()); - } - } - - if((userRequested == "" || userRequested == user) && tweets.size()) { - std::string tweetID = getMostRecentTweetID(user); - if(tweetID != tweets[0].getID()) updateLastTweetID(user, tweets[0].getID()); - } - - } else { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } -} - -void TwitterPlugin::directMessageResponse(std::string &user, std::string &username, std::vector &messages, Error &errMsg) -{ - if(errMsg.getCode() == "93") //Permission Denied - return; - - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - - if(username != "") - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("Error while sending direct message! - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - else - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("Error while fetching direct messages! - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - return; - } - - if(username != "") { - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - "Message delivered!", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - return; - } - - if(!messages.size()) return; - - if(userdb[user].twitterMode == SINGLECONTACT) { - - std::string msglist = ""; - std::string msgID = getMostRecentDMID(user); - std::string maxID = msgID; - - for(int i=0 ; i < messages.size() ; i++) { - if(cmp(msgID, messages[i].getID()) == -1) { - msglist += " - " + messages[i].getSenderData().getScreenName() + ": " + messages[i].getMessage() + "\n"; - if(cmp(maxID, messages[i].getID()) == -1) maxID = messages[i].getID(); - } - } - - if(msglist.length()) handleMessage(user, adminLegacyName, msglist, ""); - updateLastDMID(user, maxID); - - } else { - - std::string msgID = getMostRecentDMID(user); - std::string maxID = msgID; - - for(int i=0 ; i < messages.size() ; i++) { - if(cmp(msgID, messages[i].getID()) == -1) { - if(userdb[user].twitterMode == MULTIPLECONTACT) - handleMessage(user, messages[i].getSenderData().getScreenName(), messages[i].getMessage(), ""); - else - handleMessage(user, adminChatRoom, messages[i].getMessage() + " - ", messages[i].getSenderData().getScreenName()); - if(cmp(maxID, messages[i].getID()) == -1) maxID = messages[i].getID(); - } - } - - if(maxID == getMostRecentDMID(user)) LOG4CXX_INFO(logger, "No new direct messages for " << user) - updateLastDMID(user, maxID); - } -} - -void TwitterPlugin::createFriendResponse(std::string &user, User &frnd, std::string &img, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - return; - } - - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("You are now following ") + frnd.getScreenName(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - - userdb[user].buddies.insert(frnd.getScreenName()); - userdb[user].buddiesInfo[frnd.getScreenName()] = frnd; - userdb[user].buddiesImgs[frnd.getScreenName()] = img; - - LOG4CXX_INFO(logger, user << " - " << frnd.getScreenName() << ", " << frnd.getProfileImgURL()) - if(userdb[user].twitterMode == MULTIPLECONTACT) { -#if HAVE_SWIFTEN_3 - handleBuddyChanged(user, frnd.getScreenName(), frnd.getUserName(), std::vector(), pbnetwork::STATUS_ONLINE, "", Swift::byteArrayToString(cryptoProvider->getSHA1Hash(Swift::createByteArray(img)))); -#else - handleBuddyChanged(user, frnd.getScreenName(), frnd.getUserName(), std::vector(), pbnetwork::STATUS_ONLINE, "", SHA(img)); -#endif - } else if(userdb[user].twitterMode == CHATROOM) { - handleParticipantChanged(user, frnd.getScreenName(), adminChatRoom, 0, pbnetwork::STATUS_ONLINE); - } -} - -void TwitterPlugin::deleteFriendResponse(std::string &user, User &frnd, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - return; - } - - LOG4CXX_INFO(logger, user << " - " << frnd.getScreenName() << ", " << frnd.getProfileImgURL()) - userdb[user].buddies.erase(frnd.getScreenName()); - - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - std::string("You are not following ") + frnd.getScreenName() + " anymore", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - - if (userdb[user].twitterMode == CHATROOM) { - handleParticipantChanged(user, frnd.getScreenName(), adminLegacyName, 0, pbnetwork::STATUS_NONE); - } - - if(userdb[user].twitterMode == MULTIPLECONTACT) { - handleBuddyRemoved(user, frnd.getScreenName()); - } -} - - -void TwitterPlugin::RetweetResponse(std::string &user, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } else { - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - "Retweet successful", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } -} - -void TwitterPlugin::profileImageResponse(std::string &user, std::string &buddy, std::string &img, unsigned int reqID, Error &errMsg) -{ - if(errMsg.getMessage().length()) { - if (errMsg.isCurlError()) { - handleDisconnected(user, 3, errMsg.getMessage()); - return; - } - handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); - } else { - LOG4CXX_INFO(logger, user << " - Sending VCard for " << buddy) - handleVCard(user, reqID, buddy, buddy, "", img); - } -} +#include "TwitterPlugin.h" +#include "Requests/StatusUpdateRequest.h" +#include "Requests/DirectMessageRequest.h" +#include "Requests/TimelineRequest.h" +#include "Requests/FetchFriends.h" +#include "Requests/HelpMessageRequest.h" +#include "Requests/PINExchangeProcess.h" +#include "Requests/OAuthFlow.h" +#include "Requests/CreateFriendRequest.h" +#include "Requests/DestroyFriendRequest.h" +#include "Requests/RetweetRequest.h" +#include "Requests/ProfileImageRequest.h" +#include "Swiften/StringCodecs/Hexify.h" + +DEFINE_LOGGER(logger, "Twitter Backend"); + +TwitterPlugin *np = NULL; +Swift::SimpleEventLoop *loop_; // Event Loop + +const std::string OLD_APP_KEY = "PCWAdQpyyR12ezp2fVwEhw"; +const std::string OLD_APP_SECRET = "EveLmCXJIg2R7BTCpm6OWV8YyX49nI0pxnYXh7JMvDg"; + +#define abs(x) ((x)<0?-(x):(x)) +#define SHA(x) (Swift::Hexify::hexify(Swift::SHA1::getHash(Swift::createByteArray((x))))) + +//Compares two +ve intergers 'a' and 'b' represented as strings +static int cmp(std::string a, std::string b) +{ + int diff = abs((int)a.size() - (int)b.size()); + if(a.size() < b.size()) a = std::string(diff,'0') + a; + else b = std::string(diff,'0') + b; + + if(a == b) return 0; + if(a < b) return -1; + return 1; +} + + +TwitterPlugin::TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, StorageBackend *storagebackend, const std::string &host, int port) : NetworkPlugin() +{ + this->config = config; + this->storagebackend = storagebackend; + this->m_firstPing = true; + + if (CONFIG_HAS_KEY(config, "twitter.consumer_key") == false) { + consumerKey = "5mFePMiJi0KpeURONkelg"; + } + else { + consumerKey = CONFIG_STRING(config, "twitter.consumer_key"); + } + if (CONFIG_HAS_KEY(config, "twitter.consumer_secret") == false) { + consumerSecret = "YFZCDJwRhbkccXEnaYr1waCQejTJcOY8F7l5Wim3FA"; + } + else { + consumerSecret = CONFIG_STRING(config, "twitter.consumer_secret"); + } + + if (consumerSecret.empty() || consumerKey.empty()) { + LOG4CXX_ERROR(logger, "Consumer key and Consumer secret can't be empty."); + exit(1); + } + + adminLegacyName = "twitter.com"; + adminChatRoom = "#twitter"; + adminNickName = "twitter"; + adminAlias = "twitter"; + + OAUTH_KEY = "twitter_oauth_token"; + OAUTH_SECRET = "twitter_oauth_secret"; + MODE = "mode"; + + m_factories = new Swift::BoostNetworkFactories(loop); + m_conn = m_factories->getConnectionFactory()->createConnection(); + m_conn->onDataRead.connect(boost::bind(&TwitterPlugin::_handleDataRead, this, _1)); + m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); + + tp = new ThreadPool(loop_, 10); + + tweet_timer = m_factories->getTimerFactory()->createTimer(90000); + message_timer = m_factories->getTimerFactory()->createTimer(90000); + + tweet_timer->onTick.connect(boost::bind(&TwitterPlugin::pollForTweets, this)); + message_timer->onTick.connect(boost::bind(&TwitterPlugin::pollForDirectMessages, this)); + + tweet_timer->start(); + message_timer->start(); + + LOG4CXX_INFO(logger, "Starting the plugin."); +} + +TwitterPlugin::~TwitterPlugin() +{ + delete storagebackend; + std::set::iterator it; + for(it = onlineUsers.begin() ; it != onlineUsers.end() ; it++) delete userdb[*it].sessions; + delete tp; +} + +// Send data to NetworkPlugin server +void TwitterPlugin::sendData(const std::string &string) +{ + m_conn->write(Swift::createSafeByteArray(string)); +} + +// Receive date from the NetworkPlugin server and invoke the appropirate payload handler (implement in the NetworkPlugin class) +void TwitterPlugin::_handleDataRead(boost::shared_ptr data) +{ + if (m_firstPing) { + m_firstPing = false; + // Users can join the network without registering if we allow + // one user to connect multiple IRC networks. + NetworkPlugin::PluginConfig cfg; + cfg.setNeedPassword(false); + sendConfig(cfg); + } + + std::string d(data->begin(), data->end()); + handleDataRead(d); +} + +// User trying to login into his twitter account +void TwitterPlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) +{ + if(userdb.count(user) && (userdb[user].connectionState == NEW || + userdb[user].connectionState == CONNECTED || + userdb[user].connectionState == WAITING_FOR_PIN)) { + LOG4CXX_INFO(logger, std::string("A session corresponding to ") + user + std::string(" is already active")) + return; + } + + LOG4CXX_INFO(logger, std::string("Received login request for ") + user) + initUserSession(user, legacyName, password); + handleConnected(user); + + LOG4CXX_INFO(logger, "SPECTRUM 1 USER? - " << (userdb[user].spectrum1User? "true" : "false")) + + LOG4CXX_INFO(logger, user << ": Adding Buddy " << adminLegacyName << " " << adminAlias) + handleBuddyChanged(user, adminLegacyName, adminAlias, std::vector(), pbnetwork::STATUS_ONLINE); + userdb[user].nickName = ""; + + LOG4CXX_INFO(logger, "Querying database for usersettings of " << user) + std::string key, secret; + getUserOAuthKeyAndSecret(user, key, secret); + + if(key == "" || secret == "") { + LOG4CXX_INFO(logger, "Intiating OAuth Flow for user " << user) + setTwitterMode(user, 0); + tp->runAsThread(new OAuthFlow(np, userdb[user].sessions, user, userdb[user].sessions->getTwitterUsername())); + } else { + LOG4CXX_INFO(logger, user << " is already registerd. Using the stored oauth key and secret") + LOG4CXX_INFO(logger, key << " " << secret) + pinExchangeComplete(user, key, secret); + } +} + +// User logging out +void TwitterPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) +{ + if (userdb.count(user)) { + delete userdb[user].sessions; + userdb[user].sessions = NULL; + userdb[user].connectionState = DISCONNECTED; + } + + if(onlineUsers.count(user)) { + onlineUsers.erase(user); + } +} + +// User joining a Chatroom +void TwitterPlugin::handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) +{ + if(room == adminChatRoom) { + LOG4CXX_INFO(logger, "Received Join Twitter room request for " << user) + + setTwitterMode(user, 2); + handleParticipantChanged(user, adminNickName, room, 0, pbnetwork::STATUS_ONLINE); + userdb[user].nickName = nickname; + handleMessage(user, adminChatRoom, "Connected to Twitter room! Populating your followers list", adminNickName); + tp->runAsThread(new FetchFriends(userdb[user].sessions, user, + boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); + } else { + setTwitterMode(user, 0); + LOG4CXX_ERROR(logger, "Couldn't connect to chatroom - " << room <<"! Try twitter-chatroom as the chatroom to access Twitter account") + handleMessage(user, adminLegacyName, "Couldn't connect to chatroom! Try twitter-chatroom as the chatroom to access Twitter account"); + } +} + +// User leaving a Chatroom +void TwitterPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) +{ + if(room == adminChatRoom && onlineUsers.count(user)) { + LOG4CXX_INFO(logger, "Leaving chatroom! Switching back to default mode 0") + setTwitterMode(user, 0); + handleBuddyChanged(user, adminLegacyName, adminAlias, std::vector(), pbnetwork::STATUS_ONLINE); + } +} + +// Messages to be sent to Twitter +void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &/*id*/) +{ + + LOG4CXX_INFO(logger, "Received " << user << " --> " << legacyName << " - " << message) + + if(legacyName == adminLegacyName || legacyName == adminChatRoom) { + std::string cmd = "", data = ""; + + /** Parsing the message - Assuming message format to be [ ]***/ + int i; + for(i=0 ; irunAsThread(new PINExchangeProcess(np, userdb[user].sessions, user, data)); + else if(cmd == "#help") + tp->runAsThread(new HelpMessageRequest(user, CONFIG_STRING(config, "service.jid"), boost::bind(&TwitterPlugin::helpMessageResponse, this, _1, _2))); + else if(cmd[0] == '@') { + std::string username = cmd.substr(1); + tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, username, data, + boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); + } + else if(cmd == "#status") + tp->runAsThread(new StatusUpdateRequest(userdb[user].sessions, user, data, + boost::bind(&TwitterPlugin::statusUpdateResponse, this, _1, _2))); + else if(cmd == "#timeline") + tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, data, "", + boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); + else if(cmd == "#friends") + tp->runAsThread(new FetchFriends(userdb[user].sessions, user, + boost::bind(&TwitterPlugin::displayFriendlist, this, _1, _2, _3, _4))); + else if(cmd == "#follow") + tp->runAsThread(new CreateFriendRequest(userdb[user].sessions, user, data.substr(0,data.find('@')), + boost::bind(&TwitterPlugin::createFriendResponse, this, _1, _2, _3, _4))); + else if(cmd == "#unfollow") + tp->runAsThread(new DestroyFriendRequest(userdb[user].sessions, user, data.substr(0,data.find('@')), + boost::bind(&TwitterPlugin::deleteFriendResponse, this, _1, _2, _3))); + else if(cmd == "#retweet") + tp->runAsThread(new RetweetRequest(userdb[user].sessions, user, data, + boost::bind(&TwitterPlugin::RetweetResponse, this, _1, _2))); + else if(cmd == "#mode") { + int m = 0; + m = atoi(data.c_str()); + mode prevm = userdb[user].twitterMode; + + if((mode)m == userdb[user].twitterMode) return; //If same as current mode return + if(m < 0 || m > 2) { // Invalid modes + handleMessage(user, adminLegacyName, std::string("Error! Unknown mode ") + data + ". Allowed values 0,1,2." ); + return; + } + + setTwitterMode(user, m); + if((userdb[user].twitterMode == SINGLECONTACT || userdb[user].twitterMode == CHATROOM) && prevm == MULTIPLECONTACT) clearRoster(user); + else if(userdb[user].twitterMode == MULTIPLECONTACT) + tp->runAsThread(new FetchFriends(userdb[user].sessions, user, boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); + + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("Changed mode to ") + data, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + + LOG4CXX_INFO(logger, user << ": Changed mode to " << data << " <" << (userdb[user].twitterMode == CHATROOM ? adminNickName : "") << ">" ) + } + + else if(userdb[user].twitterMode == CHATROOM) { + std::string buddy = message.substr(0, message.find(":")); + if(userdb[user].buddies.count(buddy) == 0) { + tp->runAsThread(new StatusUpdateRequest(userdb[user].sessions, user, message, + boost::bind(&TwitterPlugin::statusUpdateResponse, this, _1, _2))); + } else { + data = message.substr(message.find(":")+1); //Can parse better??:P + tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, data, + boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); + } + } + else handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + "Unknown command! Type #help for a list of available commands.", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } + + else { + std::string buddy = legacyName; + if(userdb[user].twitterMode == CHATROOM) buddy = legacyName.substr(legacyName.find("/") + 1); + if(legacyName != "twitter") { + tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, message, + boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); + } + } +} + +void TwitterPlugin::handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) +{ + if(userdb[user].connectionState != CONNECTED) { + LOG4CXX_ERROR(logger, user << " is not connected to twitter!") + return; + } + + LOG4CXX_INFO(logger, user << " - Adding Twitter contact " << buddyName) + tp->runAsThread(new CreateFriendRequest(userdb[user].sessions, user, buddyName, + boost::bind(&TwitterPlugin::createFriendResponse, this, _1, _2, _3, _4))); +} + +void TwitterPlugin::handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) +{ + if(userdb[user].connectionState != CONNECTED) { + LOG4CXX_ERROR(logger, user << " is not connected to twitter!") + return; + } + + LOG4CXX_INFO(logger, user << " - Removing Twitter contact " << buddyName) + tp->runAsThread(new DestroyFriendRequest(userdb[user].sessions, user, buddyName, + boost::bind(&TwitterPlugin::deleteFriendResponse, this, _1, _2, _3))); +} + +void TwitterPlugin::handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) +{ + if(userdb[user].connectionState != CONNECTED) { + LOG4CXX_ERROR(logger, user << " is not connected to twitter!") + return; + } + + LOG4CXX_INFO(logger, user << " - VCardRequest for " << legacyName << ", " << userdb[user].buddiesInfo[legacyName].getProfileImgURL()) + + if(getTwitterMode(user) != SINGLECONTACT && userdb[user].buddies.count(legacyName) + && userdb[user].buddiesInfo[legacyName].getProfileImgURL().length()) { + if(userdb[user].buddiesImgs.count(legacyName) == 0) { + tp->runAsThread(new ProfileImageRequest(config, user, legacyName, userdb[user].buddiesInfo[legacyName].getProfileImgURL(), id, + boost::bind(&TwitterPlugin::profileImageResponse, this, _1, _2, _3, _4, _5))); + } + handleVCard(user, id, legacyName, legacyName, "", userdb[user].buddiesImgs[legacyName]); + } +} + +void TwitterPlugin::pollForTweets() +{ + boost::mutex::scoped_lock lock(userlock); + std::set::iterator it = onlineUsers.begin(); + while(it != onlineUsers.end()) { + std::string user = *it; + tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, "", getMostRecentTweetIDUnsafe(user), + boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); + it++; + } + tweet_timer->start(); +} + +void TwitterPlugin::pollForDirectMessages() +{ + boost::mutex::scoped_lock lock(userlock); + std::set::iterator it = onlineUsers.begin(); + while(it != onlineUsers.end()) { + std::string user = *it; + tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, "", getMostRecentDMIDUnsafe(user), + boost::bind(&TwitterPlugin::directMessageResponse, this, _1, _2, _3, _4))); + it++; + } + message_timer->start(); +} + + +bool TwitterPlugin::getUserOAuthKeyAndSecret(const std::string user, std::string &key, std::string &secret) +{ + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return false; + } + + key="", secret=""; int type; + storagebackend->getUserSetting((long)info.id, OAUTH_KEY, type, key); + storagebackend->getUserSetting((long)info.id, OAUTH_SECRET, type, secret); + return true; +} + +bool TwitterPlugin::checkSpectrum1User(const std::string user) +{ + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return false; + } + + std::string first_synchronization_done = ""; + int type; + storagebackend->getUserSetting((long)info.id, "first_synchronization_done", type, first_synchronization_done); + + LOG4CXX_INFO(logger, "first_synchronization_done: " << first_synchronization_done) + + if(first_synchronization_done.length()) return true; + return false; +} + +int TwitterPlugin::getTwitterMode(const std::string user) +{ + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return -1; + } + + int type; int m; + std::string s_m; + storagebackend->getUserSetting((long)info.id, MODE, type, s_m); + if(s_m == "") { + s_m = "0"; + storagebackend->updateUserSetting((long)info.id, MODE, s_m); + } + m = atoi(s_m.c_str()); + return m; +} + +bool TwitterPlugin::setTwitterMode(const std::string user, int m) +{ + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return false; + } + + if(m < 0 || m > 2) { + LOG4CXX_ERROR(logger, "Unknown mode " << m <<". Using default mode 0") + m = 0; + } + + userdb[user].twitterMode = (mode)m; + + //int type; + std::string s_m = std::string(1,m+'0'); + LOG4CXX_ERROR(logger, "Storing mode " << m <<" for user " << user) + storagebackend->updateUserSetting((long)info.id, MODE, s_m); + return true; +} + +bool TwitterPlugin::storeUserOAuthKeyAndSecret(const std::string user, const std::string OAuthKey, const std::string OAuthSecret) +{ + + boost::mutex::scoped_lock lock(dblock); + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return false; + } + + storagebackend->updateUserSetting((long)info.id, OAUTH_KEY, OAuthKey); + storagebackend->updateUserSetting((long)info.id, OAUTH_SECRET, OAuthSecret); + return true; +} + +void TwitterPlugin::initUserSession(const std::string user, const std::string legacyName, const std::string password) +{ + boost::mutex::scoped_lock lock(userlock); + + std::string username = legacyName; + std::string passwd = password; + LOG4CXX_INFO(logger, username + " " + passwd) + + userdb[user].sessions = new twitCurl(); + if(CONFIG_HAS_KEY(config,"proxy.server")) { + std::string ip = CONFIG_STRING(config,"proxy.server"); + + std::ostringstream out; + out << CONFIG_INT(config,"proxy.port"); + std::string port = out.str(); + + std::string puser = CONFIG_STRING(config,"proxy.user"); + std::string ppasswd = CONFIG_STRING(config,"proxy.password"); + + LOG4CXX_INFO(logger, ip << " " << port << " " << puser << " " << ppasswd) + + if(ip != "localhost" && port != "0") { + userdb[user].sessions->setProxyServerIp(ip); + userdb[user].sessions->setProxyServerPort(port); + userdb[user].sessions->setProxyUserName(puser); + userdb[user].sessions->setProxyPassword(ppasswd); + } + } + + //Check if the user is spectrum1 user + userdb[user].spectrum1User = checkSpectrum1User(user); + + userdb[user].connectionState = NEW; + userdb[user].legacyName = username; + userdb[user].sessions->setTwitterUsername(username); + userdb[user].sessions->setTwitterPassword(passwd); + + if(!userdb[user].spectrum1User) { + userdb[user].sessions->getOAuth().setConsumerKey(consumerKey); + userdb[user].sessions->getOAuth().setConsumerSecret(consumerSecret); + } else { + userdb[user].sessions->getOAuth().setConsumerKey(OLD_APP_KEY); + userdb[user].sessions->getOAuth().setConsumerSecret(OLD_APP_SECRET); + } +} + +void TwitterPlugin::OAuthFlowComplete(const std::string user, twitCurl *obj) +{ + boost::mutex::scoped_lock lock(userlock); + + delete userdb[user].sessions; + userdb[user].sessions = obj->clone(); + userdb[user].connectionState = WAITING_FOR_PIN; +} + +void TwitterPlugin::pinExchangeComplete(const std::string user, const std::string OAuthAccessTokenKey, const std::string OAuthAccessTokenSecret) +{ + boost::mutex::scoped_lock lock(userlock); + + userdb[user].sessions->getOAuth().setOAuthTokenKey( OAuthAccessTokenKey ); + userdb[user].sessions->getOAuth().setOAuthTokenSecret( OAuthAccessTokenSecret ); + userdb[user].connectionState = CONNECTED; + userdb[user].twitterMode = (mode)getTwitterMode(user); + + if(userdb[user].twitterMode == MULTIPLECONTACT) { + tp->runAsThread(new FetchFriends(userdb[user].sessions, user, boost::bind(&TwitterPlugin::populateRoster, this, _1, _2, _3, _4))); + } + + onlineUsers.insert(user); + userdb[user].mostRecentTweetID = ""; + userdb[user].mostRecentDirectMessageID = ""; +} + +void TwitterPlugin::updateLastTweetID(const std::string user, const std::string ID) +{ + boost::mutex::scoped_lock lock(userlock); + userdb[user].mostRecentTweetID = ID; + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return; + } + + storagebackend->updateUserSetting((long)info.id, "twitter_last_tweet", ID); +} + +std::string TwitterPlugin::getMostRecentTweetIDUnsafe(const std::string user) +{ + std::string ID = ""; + if(onlineUsers.count(user)) { + ID = userdb[user].mostRecentTweetID; + if (ID.empty()) { + int type; + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + } + else { + storagebackend->getUserSetting(info.id, "twitter_last_tweet", type, ID); + } + } + } + return ID; +} + +std::string TwitterPlugin::getMostRecentTweetID(const std::string user) +{ + boost::mutex::scoped_lock lock(userlock); + return getMostRecentTweetIDUnsafe(user); +} + +void TwitterPlugin::updateLastDMID(const std::string user, const std::string ID) +{ + boost::mutex::scoped_lock lock(userlock); + userdb[user].mostRecentDirectMessageID = ID; + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return; + } + + storagebackend->updateUserSetting((long)info.id, "twitter_last_dm", ID); +} + +std::string TwitterPlugin::getMostRecentDMIDUnsafe(const std::string user) { + std::string ID = ""; + if(onlineUsers.count(user)) { + ID = userdb[user].mostRecentDirectMessageID; + if (ID.empty()) { + int type; + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + } + else { + storagebackend->getUserSetting(info.id, "twitter_last_dm", type, ID); + } + } + } + return ID; +} + +std::string TwitterPlugin::getMostRecentDMID(const std::string user) +{ + boost::mutex::scoped_lock lock(userlock); + return getMostRecentDMIDUnsafe(user); +} + +/************************************** Twitter response functions **********************************/ +void TwitterPlugin::statusUpdateResponse(std::string &user, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } else { + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + "Status Update successful", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } +} + +void TwitterPlugin::helpMessageResponse(std::string &user, std::string &msg) +{ + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + msg, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); +} + +void TwitterPlugin::clearRoster(const std::string user) +{ + if(userdb[user].buddies.size() == 0) return; + std::set::iterator it = userdb[user].buddies.begin(); + while(it != userdb[user].buddies.end()) { + handleBuddyRemoved(user, *it); + it++; + } + userdb[user].buddies.clear(); +} + +void TwitterPlugin::populateRoster(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg) +{ + if(errMsg.getMessage().length() == 0) + { + for(int i=0 ; i(), +#if HAVE_SWIFTEN_3 + pbnetwork::STATUS_ONLINE, lastTweet, Swift::byteArrayToString(cryptoProvider->getSHA1Hash(Swift::createByteArray(friendAvatars[i])))); +#else + pbnetwork::STATUS_ONLINE, lastTweet, SHA(friendAvatars[i])); +#endif + } + else if(userdb[user].twitterMode == CHATROOM) + handleParticipantChanged(user, friends[i].getScreenName(), adminChatRoom, 0, pbnetwork::STATUS_ONLINE); + + /*handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + friends[i].getScreenName() + " - " + friends[i].getLastStatus().getTweet(), + userdb[user].twitterMode == CHATROOM ? adminNickName : "");*/ + } + } else { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("Error populating roster - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } + + if(userdb[user].twitterMode == CHATROOM) handleParticipantChanged(user, userdb[user].nickName, adminChatRoom, 0, pbnetwork::STATUS_ONLINE); +} + +void TwitterPlugin::displayFriendlist(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg) +{ + if(errMsg.getMessage().length() == 0) + { + std::string userlist = "\n***************USER LIST****************\n"; + for(int i=0 ; i < friends.size() ; i++) { + userlist += " - " + friends[i].getUserName() + " (" + friends[i].getScreenName() + ")\n"; + } + userlist += "***************************************\n"; + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + userlist, userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } else { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } + +} + +void TwitterPlugin::displayTweets(std::string &user, std::string &userRequested, std::vector &tweets , Error &errMsg) +{ + if(errMsg.getMessage().length() == 0) { + std::map lastTweet; + std::map::iterator it; + + for(int i = tweets.size() - 1 ; i >= 0 ; i--) { + if(userdb[user].twitterMode != CHATROOM) { + std::string m = " - " + tweets[i].getUserData().getScreenName() + ": " + tweets[i].getTweet() + " (MsgId: " + (tweets[i].getRetweetID().empty() ? tweets[i].getID() : tweets[i].getRetweetID()) + ")\n"; + handleMessage(user, adminLegacyName, m, "", "", tweets[i].getCreationTime(), true); + + std::string scrname = tweets[i].getUserData().getScreenName(); + if(lastTweet.count(scrname) == 0 || cmp(tweets[lastTweet[scrname]].getID(), tweets[i].getID()) <= 0) lastTweet[scrname] = i; + + } else { + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + tweets[i].getTweet() + " (MsgId: " + (tweets[i].getRetweetID().empty() ? tweets[i].getID() : tweets[i].getRetweetID()) + ")", tweets[i].getUserData().getScreenName(), "", tweets[i].getCreationTime(), true); + } + } + + if(userdb[user].twitterMode == MULTIPLECONTACT) { + //Set as status user's last tweet + for(it=lastTweet.begin() ; it!=lastTweet.end() ; it++) { + int t = it->second; + handleBuddyChanged(user, tweets[t].getUserData().getScreenName(), tweets[t].getUserData().getUserName(), + std::vector(), pbnetwork::STATUS_ONLINE, tweets[t].getTweet()); + } + } + + if((userRequested == "" || userRequested == user) && tweets.size()) { + std::string tweetID = getMostRecentTweetID(user); + if(tweetID != tweets[0].getID()) updateLastTweetID(user, tweets[0].getID()); + } + + } else { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } +} + +void TwitterPlugin::directMessageResponse(std::string &user, std::string &username, std::vector &messages, Error &errMsg) +{ + if(errMsg.getCode() == "93") //Permission Denied + return; + + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + + if(username != "") + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("Error while sending direct message! - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + else + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("Error while fetching direct messages! - ") + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + return; + } + + if(username != "") { + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + "Message delivered!", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + return; + } + + if(!messages.size()) return; + + if(userdb[user].twitterMode == SINGLECONTACT) { + + std::string msglist = ""; + std::string msgID = getMostRecentDMID(user); + std::string maxID = msgID; + + for(int i=0 ; i < messages.size() ; i++) { + if(cmp(msgID, messages[i].getID()) == -1) { + msglist += " - " + messages[i].getSenderData().getScreenName() + ": " + messages[i].getMessage() + "\n"; + if(cmp(maxID, messages[i].getID()) == -1) maxID = messages[i].getID(); + } + } + + if(msglist.length()) handleMessage(user, adminLegacyName, msglist, ""); + updateLastDMID(user, maxID); + + } else { + + std::string msgID = getMostRecentDMID(user); + std::string maxID = msgID; + + for(int i=0 ; i < messages.size() ; i++) { + if(cmp(msgID, messages[i].getID()) == -1) { + if(userdb[user].twitterMode == MULTIPLECONTACT) + handleMessage(user, messages[i].getSenderData().getScreenName(), messages[i].getMessage(), ""); + else + handleMessage(user, adminChatRoom, messages[i].getMessage() + " - ", messages[i].getSenderData().getScreenName()); + if(cmp(maxID, messages[i].getID()) == -1) maxID = messages[i].getID(); + } + } + + if(maxID == getMostRecentDMID(user)) LOG4CXX_INFO(logger, "No new direct messages for " << user) + updateLastDMID(user, maxID); + } +} + +void TwitterPlugin::createFriendResponse(std::string &user, User &frnd, std::string &img, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + return; + } + + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("You are now following ") + frnd.getScreenName(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + + userdb[user].buddies.insert(frnd.getScreenName()); + userdb[user].buddiesInfo[frnd.getScreenName()] = frnd; + userdb[user].buddiesImgs[frnd.getScreenName()] = img; + + LOG4CXX_INFO(logger, user << " - " << frnd.getScreenName() << ", " << frnd.getProfileImgURL()) + if(userdb[user].twitterMode == MULTIPLECONTACT) { +#if HAVE_SWIFTEN_3 + handleBuddyChanged(user, frnd.getScreenName(), frnd.getUserName(), std::vector(), pbnetwork::STATUS_ONLINE, "", Swift::byteArrayToString(cryptoProvider->getSHA1Hash(Swift::createByteArray(img)))); +#else + handleBuddyChanged(user, frnd.getScreenName(), frnd.getUserName(), std::vector(), pbnetwork::STATUS_ONLINE, "", SHA(img)); +#endif + } else if(userdb[user].twitterMode == CHATROOM) { + handleParticipantChanged(user, frnd.getScreenName(), adminChatRoom, 0, pbnetwork::STATUS_ONLINE); + } +} + +void TwitterPlugin::deleteFriendResponse(std::string &user, User &frnd, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + return; + } + + LOG4CXX_INFO(logger, user << " - " << frnd.getScreenName() << ", " << frnd.getProfileImgURL()) + userdb[user].buddies.erase(frnd.getScreenName()); + + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + std::string("You are not following ") + frnd.getScreenName() + " anymore", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + + if (userdb[user].twitterMode == CHATROOM) { + handleParticipantChanged(user, frnd.getScreenName(), adminLegacyName, 0, pbnetwork::STATUS_NONE); + } + + if(userdb[user].twitterMode == MULTIPLECONTACT) { + handleBuddyRemoved(user, frnd.getScreenName()); + } +} + + +void TwitterPlugin::RetweetResponse(std::string &user, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } else { + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + "Retweet successful", userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } +} + +void TwitterPlugin::profileImageResponse(std::string &user, std::string &buddy, std::string &img, unsigned int reqID, Error &errMsg) +{ + if(errMsg.getMessage().length()) { + if (errMsg.isCurlError()) { + handleDisconnected(user, 3, errMsg.getMessage()); + return; + } + handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, + errMsg.getMessage(), userdb[user].twitterMode == CHATROOM ? adminNickName : ""); + } else { + LOG4CXX_INFO(logger, user << " - Sending VCard for " << buddy) + handleVCard(user, reqID, buddy, buddy, "", img); + } +} diff --git a/backends/twitter/TwitterPlugin.h b/backends/twitter/TwitterPlugin.h index 0854852edaee7bfaf8ba02eac0cfcc1298d38323..6e89f0cd978d644e16288fda55953d0d52a4af00 100644 --- a/backends/twitter/TwitterPlugin.h +++ b/backends/twitter/TwitterPlugin.h @@ -1,189 +1,189 @@ -#ifndef TWITTER_PLUGIN -#define TWITTER_PLUGIN - -#include "transport/config.h" -#include "transport/networkplugin.h" -#include "transport/logging.h" -#include "transport/sqlite3backend.h" -#include "transport/mysqlbackend.h" -#include "transport/pqxxbackend.h" -#include "transport/storagebackend.h" -#include "transport/threadpool.h" - -#include "Swiften/Swiften.h" -#ifndef _WIN32 -#include "unistd.h" -#include "signal.h" -#include "sys/wait.h" -#include "sys/signal.h" -#endif -#include -#include -#include -#include - -#include "twitcurl.h" -#include "TwitterResponseParser.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 -#if HAVE_SWIFTEN_3 -#include -#include -#else -#include "Swiften/StringCodecs/SHA1.h" -#endif -using namespace boost::filesystem; -using namespace boost::program_options; -using namespace Transport; - -#define STR(x) (std::string("(") + x.from + ", " + x.to + ", " + x.message + ")") - -class TwitterPlugin; -extern TwitterPlugin *np; -extern Swift::SimpleEventLoop *loop_; // Event Loop - - -class TwitterPlugin : public NetworkPlugin { - public: - Swift::BoostNetworkFactories *m_factories; - Swift::BoostIOServiceThread m_boostIOServiceThread; - boost::shared_ptr m_conn; -#if HAVE_SWIFTEN_3 - boost::shared_ptr cryptoProvider; -#endif - Swift::Timer::ref tweet_timer; - Swift::Timer::ref message_timer; - StorageBackend *storagebackend; - - TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, StorageBackend *storagebackend, const std::string &host, int port); - ~TwitterPlugin(); - - // Send data to NetworkPlugin server - void sendData(const std::string &string); - - // Receive date from the NetworkPlugin server and invoke the appropirate payload handler (implement in the NetworkPlugin class) - void _handleDataRead(boost::shared_ptr data); - - // User trying to login into his twitter account - void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password); - - // User logging out - void handleLogoutRequest(const std::string &user, const std::string &legacyName); - - void handleJoinRoomRequest(const std::string &/*user*/, const std::string &/*room*/, const std::string &/*nickname*/, const std::string &/*pasword*/); - - void handleLeaveRoomRequest(const std::string &/*user*/, const std::string &/*room*/); - - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = ""); - - void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups); - - void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups); - - void handleVCardRequest(const std::string &/*user*/, const std::string &/*legacyName*/, unsigned int /*id*/); - - void pollForTweets(); - - void pollForDirectMessages(); - - bool getUserOAuthKeyAndSecret(const std::string user, std::string &key, std::string &secret); - - bool checkSpectrum1User(const std::string user); - - bool storeUserOAuthKeyAndSecret(const std::string user, const std::string OAuthKey, const std::string OAuthSecret); - - void initUserSession(const std::string user, const std::string legacyName, const std::string password); - - void OAuthFlowComplete(const std::string user, twitCurl *obj); - - void pinExchangeComplete(const std::string user, const std::string OAuthAccessTokenKey, const std::string OAuthAccessTokenSecret); - - void updateLastTweetID(const std::string user, const std::string ID); - - std::string getMostRecentTweetID(const std::string user); - - void updateLastDMID(const std::string user, const std::string ID); - - std::string getMostRecentDMID(const std::string user); - - void clearRoster(const std::string user); - - int getTwitterMode(const std::string user); - - bool setTwitterMode(const std::string user, int m); - - /****************** Twitter response handlers **************************************/ - void statusUpdateResponse(std::string &user, Error &errMsg); - - void helpMessageResponse(std::string &user, std::string &msg); - - void populateRoster(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg); - - void displayFriendlist(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg); - - void displayTweets(std::string &user, std::string &userRequested, std::vector &tweets , Error &errMsg); - - void directMessageResponse(std::string &user, std::string &username, std::vector &messages, Error &errMsg); - - void createFriendResponse(std::string &user, User &frnd, std::string &img, Error &errMsg); - - void deleteFriendResponse(std::string &user, User &frnd, Error &errMsg); - - void RetweetResponse(std::string &user, Error &errMsg); - - void profileImageResponse(std::string &user, std::string &buddy, std::string &img, unsigned int reqID, Error &errMsg); - /***********************************************************************************/ - - private: - std::string getMostRecentTweetIDUnsafe(const std::string user); - std::string getMostRecentDMIDUnsafe(const std::string user); - - enum status {NEW, WAITING_FOR_PIN, CONNECTED, DISCONNECTED}; - enum mode {SINGLECONTACT, MULTIPLECONTACT, CHATROOM}; - - Config *config; - std::string adminLegacyName; - std::string adminChatRoom; - std::string adminNickName; - std::string adminAlias; - - std::string consumerKey; - std::string consumerSecret; - std::string OAUTH_KEY; - std::string OAUTH_SECRET; - std::string MODE; - - boost::mutex dblock, userlock; - - ThreadPool *tp; - std::set onlineUsers; - struct UserData - { - std::string legacyName; - bool spectrum1User; //Legacy support - User userTwitterObj; - std::string userImg; - twitCurl* sessions; - status connectionState; - std::string mostRecentTweetID; - std::string mostRecentDirectMessageID; - std::string nickName; - std::set buddies; - std::map buddiesInfo; - std::map buddiesImgs; - mode twitterMode; - - UserData() { sessions = NULL; } - }; - std::map userdb; - bool m_firstPing; -}; -#endif +#ifndef TWITTER_PLUGIN +#define TWITTER_PLUGIN + +#include "transport/config.h" +#include "transport/networkplugin.h" +#include "transport/logging.h" +#include "transport/sqlite3backend.h" +#include "transport/mysqlbackend.h" +#include "transport/pqxxbackend.h" +#include "transport/storagebackend.h" +#include "transport/threadpool.h" + +#include "Swiften/Swiften.h" +#ifndef _WIN32 +#include "unistd.h" +#include "signal.h" +#include "sys/wait.h" +#include "sys/signal.h" +#endif +#include +#include +#include +#include + +#include "twitcurl.h" +#include "TwitterResponseParser.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 +#if HAVE_SWIFTEN_3 +#include +#include +#else +#include "Swiften/StringCodecs/SHA1.h" +#endif +using namespace boost::filesystem; +using namespace boost::program_options; +using namespace Transport; + +#define STR(x) (std::string("(") + x.from + ", " + x.to + ", " + x.message + ")") + +class TwitterPlugin; +extern TwitterPlugin *np; +extern Swift::SimpleEventLoop *loop_; // Event Loop + + +class TwitterPlugin : public NetworkPlugin { + public: + Swift::BoostNetworkFactories *m_factories; + Swift::BoostIOServiceThread m_boostIOServiceThread; + boost::shared_ptr m_conn; +#if HAVE_SWIFTEN_3 + boost::shared_ptr cryptoProvider; +#endif + Swift::Timer::ref tweet_timer; + Swift::Timer::ref message_timer; + StorageBackend *storagebackend; + + TwitterPlugin(Config *config, Swift::SimpleEventLoop *loop, StorageBackend *storagebackend, const std::string &host, int port); + ~TwitterPlugin(); + + // Send data to NetworkPlugin server + void sendData(const std::string &string); + + // Receive date from the NetworkPlugin server and invoke the appropirate payload handler (implement in the NetworkPlugin class) + void _handleDataRead(boost::shared_ptr data); + + // User trying to login into his twitter account + void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password); + + // User logging out + void handleLogoutRequest(const std::string &user, const std::string &legacyName); + + void handleJoinRoomRequest(const std::string &/*user*/, const std::string &/*room*/, const std::string &/*nickname*/, const std::string &/*pasword*/); + + void handleLeaveRoomRequest(const std::string &/*user*/, const std::string &/*room*/); + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = ""); + + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups); + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups); + + void handleVCardRequest(const std::string &/*user*/, const std::string &/*legacyName*/, unsigned int /*id*/); + + void pollForTweets(); + + void pollForDirectMessages(); + + bool getUserOAuthKeyAndSecret(const std::string user, std::string &key, std::string &secret); + + bool checkSpectrum1User(const std::string user); + + bool storeUserOAuthKeyAndSecret(const std::string user, const std::string OAuthKey, const std::string OAuthSecret); + + void initUserSession(const std::string user, const std::string legacyName, const std::string password); + + void OAuthFlowComplete(const std::string user, twitCurl *obj); + + void pinExchangeComplete(const std::string user, const std::string OAuthAccessTokenKey, const std::string OAuthAccessTokenSecret); + + void updateLastTweetID(const std::string user, const std::string ID); + + std::string getMostRecentTweetID(const std::string user); + + void updateLastDMID(const std::string user, const std::string ID); + + std::string getMostRecentDMID(const std::string user); + + void clearRoster(const std::string user); + + int getTwitterMode(const std::string user); + + bool setTwitterMode(const std::string user, int m); + + /****************** Twitter response handlers **************************************/ + void statusUpdateResponse(std::string &user, Error &errMsg); + + void helpMessageResponse(std::string &user, std::string &msg); + + void populateRoster(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg); + + void displayFriendlist(std::string &user, std::vector &friends, std::vector &friendAvatars, Error &errMsg); + + void displayTweets(std::string &user, std::string &userRequested, std::vector &tweets , Error &errMsg); + + void directMessageResponse(std::string &user, std::string &username, std::vector &messages, Error &errMsg); + + void createFriendResponse(std::string &user, User &frnd, std::string &img, Error &errMsg); + + void deleteFriendResponse(std::string &user, User &frnd, Error &errMsg); + + void RetweetResponse(std::string &user, Error &errMsg); + + void profileImageResponse(std::string &user, std::string &buddy, std::string &img, unsigned int reqID, Error &errMsg); + /***********************************************************************************/ + + private: + std::string getMostRecentTweetIDUnsafe(const std::string user); + std::string getMostRecentDMIDUnsafe(const std::string user); + + enum status {NEW, WAITING_FOR_PIN, CONNECTED, DISCONNECTED}; + enum mode {SINGLECONTACT, MULTIPLECONTACT, CHATROOM}; + + Config *config; + std::string adminLegacyName; + std::string adminChatRoom; + std::string adminNickName; + std::string adminAlias; + + std::string consumerKey; + std::string consumerSecret; + std::string OAUTH_KEY; + std::string OAUTH_SECRET; + std::string MODE; + + boost::mutex dblock, userlock; + + ThreadPool *tp; + std::set onlineUsers; + struct UserData + { + std::string legacyName; + bool spectrum1User; //Legacy support + User userTwitterObj; + std::string userImg; + twitCurl* sessions; + status connectionState; + std::string mostRecentTweetID; + std::string mostRecentDirectMessageID; + std::string nickName; + std::set buddies; + std::map buddiesInfo; + std::map buddiesImgs; + mode twitterMode; + + UserData() { sessions = NULL; } + }; + std::map userdb; + bool m_firstPing; +}; +#endif diff --git a/backends/twitter/libtwitcurl/HMAC_SHA1.cpp b/backends/twitter/libtwitcurl/HMAC_SHA1.cpp index 5382782e610612e3d9d029e18f533044c8e06508..9ed68144e2ab8f5b27787bbd30d1383b2366dcbc 100644 --- a/backends/twitter/libtwitcurl/HMAC_SHA1.cpp +++ b/backends/twitter/libtwitcurl/HMAC_SHA1.cpp @@ -1,64 +1,64 @@ -//****************************************************************************** -//* HMAC_SHA1.cpp : Implementation of HMAC SHA1 algorithm -//* Comfort to RFC 2104 -//* -//****************************************************************************** -#include "HMAC_SHA1.h" -#include -#include - - -void CHMAC_SHA1::HMAC_SHA1(BYTE *text, int text_len, BYTE *key, int key_len, BYTE *digest) -{ - memset(SHA1_Key, 0, SHA1_BLOCK_SIZE); - - /* repeated 64 times for values in ipad and opad */ - memset(m_ipad, 0x36, sizeof(m_ipad)); - memset(m_opad, 0x5c, sizeof(m_opad)); - - /* STEP 1 */ - if (key_len > SHA1_BLOCK_SIZE) - { - CSHA1::Reset(); - CSHA1::Update((UINT_8 *)key, key_len); - CSHA1::Final(); - - CSHA1::GetHash((UINT_8 *)SHA1_Key); - } - else - memcpy(SHA1_Key, key, key_len); - - /* STEP 2 */ - for (size_t i=0; i +#include + + +void CHMAC_SHA1::HMAC_SHA1(BYTE *text, int text_len, BYTE *key, int key_len, BYTE *digest) +{ + memset(SHA1_Key, 0, SHA1_BLOCK_SIZE); + + /* repeated 64 times for values in ipad and opad */ + memset(m_ipad, 0x36, sizeof(m_ipad)); + memset(m_opad, 0x5c, sizeof(m_opad)); + + /* STEP 1 */ + if (key_len > SHA1_BLOCK_SIZE) + { + CSHA1::Reset(); + CSHA1::Update((UINT_8 *)key, key_len); + CSHA1::Final(); + + CSHA1::GetHash((UINT_8 *)SHA1_Key); + } + else + memcpy(SHA1_Key, key, key_len); + + /* STEP 2 */ + for (size_t i=0; i -*/ - - -#ifndef __HMAC_SHA1_H__ -#define __HMAC_SHA1_H__ - -#include "SHA1.h" - -typedef unsigned char BYTE ; - -class CHMAC_SHA1 : public CSHA1 -{ - private: - BYTE m_ipad[64]; - BYTE m_opad[64]; - - char * szReport ; - char * SHA1_Key ; - char * AppendBuf1 ; - char * AppendBuf2 ; - - - public: - - enum { - SHA1_DIGEST_LENGTH = 20, - SHA1_BLOCK_SIZE = 64, - HMAC_BUF_LEN = 4096 - } ; - - CHMAC_SHA1() - :szReport(new char[HMAC_BUF_LEN]), - SHA1_Key(new char[HMAC_BUF_LEN]), - AppendBuf1(new char[HMAC_BUF_LEN]), - AppendBuf2(new char[HMAC_BUF_LEN]) - {} - - ~CHMAC_SHA1() - { - delete[] szReport ; - delete[] AppendBuf1 ; - delete[] AppendBuf2 ; - delete[] SHA1_Key ; - } - - void HMAC_SHA1(BYTE *text, int text_len, BYTE *key, int key_len, BYTE *digest); -}; - - -#endif /* __HMAC_SHA1_H__ */ +/* + 100% free public domain implementation of the HMAC-SHA1 algorithm + by Chien-Chung, Chung (Jim Chung) +*/ + + +#ifndef __HMAC_SHA1_H__ +#define __HMAC_SHA1_H__ + +#include "SHA1.h" + +typedef unsigned char BYTE ; + +class CHMAC_SHA1 : public CSHA1 +{ + private: + BYTE m_ipad[64]; + BYTE m_opad[64]; + + char * szReport ; + char * SHA1_Key ; + char * AppendBuf1 ; + char * AppendBuf2 ; + + + public: + + enum { + SHA1_DIGEST_LENGTH = 20, + SHA1_BLOCK_SIZE = 64, + HMAC_BUF_LEN = 4096 + } ; + + CHMAC_SHA1() + :szReport(new char[HMAC_BUF_LEN]), + SHA1_Key(new char[HMAC_BUF_LEN]), + AppendBuf1(new char[HMAC_BUF_LEN]), + AppendBuf2(new char[HMAC_BUF_LEN]) + {} + + ~CHMAC_SHA1() + { + delete[] szReport ; + delete[] AppendBuf1 ; + delete[] AppendBuf2 ; + delete[] SHA1_Key ; + } + + void HMAC_SHA1(BYTE *text, int text_len, BYTE *key, int key_len, BYTE *digest); +}; + + +#endif /* __HMAC_SHA1_H__ */ diff --git a/backends/twitter/libtwitcurl/SHA1.cpp b/backends/twitter/libtwitcurl/SHA1.cpp index c3846ee5ef3409444582e9d0b69674af2c625a41..598d879c280f7f47629793ca9694013d7ff11843 100644 --- a/backends/twitter/libtwitcurl/SHA1.cpp +++ b/backends/twitter/libtwitcurl/SHA1.cpp @@ -1,274 +1,274 @@ -/* - 100% free public domain implementation of the SHA-1 algorithm - by Dominik Reichl - Web: http://www.dominik-reichl.de/ - - Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches) - - You can set the endianness in your files, no need to modify the - header file of the CSHA1 class any more - - Aligned data support - - Made support/compilation of the utility functions (ReportHash - and HashFile) optional (useful, if bytes count, for example in - embedded environments) - - Version 1.5 - 2005-01-01 - - 64-bit compiler compatibility added - - Made variable wiping optional (define SHA1_WIPE_VARIABLES) - - Removed unnecessary variable initializations - - ROL32 improvement for the Microsoft compiler (using _rotl) - - ======== Test Vectors (from FIPS PUB 180-1) ======== - - SHA1("abc") = - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D - - SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 - - SHA1(A million repetitions of "a") = - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -#include "SHA1.h" - -#ifdef SHA1_UTILITY_FUNCTIONS -#define SHA1_MAX_FILE_BUFFER 8000 -#endif - -// Rotate x bits to the left -#ifndef ROL32 -#ifdef _MSC_VER -#define ROL32(_val32, _nBits) _rotl(_val32, _nBits) -#else -#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits)))) -#endif -#endif - -#ifdef SHA1_LITTLE_ENDIAN -#define SHABLK0(i) (m_block->l[i] = \ - (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF)) -#else -#define SHABLK0(i) (m_block->l[i]) -#endif - -#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \ - ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1)) - -// SHA-1 rounds -#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } -#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } -#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); } -#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); } -#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); } - -CSHA1::CSHA1() -{ - m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace; - - Reset(); -} - -CSHA1::~CSHA1() -{ - Reset(); -} - -void CSHA1::Reset() -{ - // SHA1 initialization constants - m_state[0] = 0x67452301; - m_state[1] = 0xEFCDAB89; - m_state[2] = 0x98BADCFE; - m_state[3] = 0x10325476; - m_state[4] = 0xC3D2E1F0; - - m_count[0] = 0; - m_count[1] = 0; -} - -void CSHA1::Transform(UINT_32 *state, UINT_8 *buffer) -{ - // Copy state[] to working vars - UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; - - memcpy(m_block, buffer, 64); - - // 4 rounds of 20 operations each. Loop unrolled. - _R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3); - _R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7); - _R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11); - _R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15); - _R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19); - _R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23); - _R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27); - _R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31); - _R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35); - _R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39); - _R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43); - _R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47); - _R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51); - _R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55); - _R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59); - _R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63); - _R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67); - _R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71); - _R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75); - _R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79); - - // Add the working vars back into state - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - - // Wipe variables -#ifdef SHA1_WIPE_VARIABLES - a = b = c = d = e = 0; -#endif -} - -// Use this function to hash in binary data and strings -void CSHA1::Update(UINT_8 *data, UINT_32 len) -{ - UINT_32 i, j; - - j = (m_count[0] >> 3) & 63; - - if((m_count[0] += len << 3) < (len << 3)) m_count[1]++; - - m_count[1] += (len >> 29); - - if((j + len) > 63) - { - i = 64 - j; - memcpy(&m_buffer[j], data, i); - Transform(m_state, m_buffer); - - for(; i + 63 < len; i += 64) Transform(m_state, &data[i]); - - j = 0; - } - else i = 0; - - memcpy(&m_buffer[j], &data[i], len - i); -} - -#ifdef SHA1_UTILITY_FUNCTIONS -// Hash in file contents -bool CSHA1::HashFile(char *szFileName) -{ - unsigned long ulFileSize, ulRest, ulBlocks; - unsigned long i; - UINT_8 uData[SHA1_MAX_FILE_BUFFER]; - FILE *fIn; - - if(szFileName == NULL) return false; - - fIn = fopen(szFileName, "rb"); - if(fIn == NULL) return false; - - fseek(fIn, 0, SEEK_END); - ulFileSize = (unsigned long)ftell(fIn); - fseek(fIn, 0, SEEK_SET); - - if(ulFileSize != 0) - { - ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER; - ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER; - } - else - { - ulBlocks = 0; - ulRest = 0; - } - - for(i = 0; i < ulBlocks; i++) - { - fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn); - Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER); - } - - if(ulRest != 0) - { - fread(uData, 1, ulRest, fIn); - Update((UINT_8 *)uData, ulRest); - } - - fclose(fIn); fIn = NULL; - return true; -} -#endif - -void CSHA1::Final() -{ - UINT_32 i; - UINT_8 finalcount[8]; - - for(i = 0; i < 8; i++) - finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)] - >> ((3 - (i & 3)) * 8) ) & 255); // Endian independent - - Update((UINT_8 *)"\200", 1); - - while ((m_count[0] & 504) != 448) - Update((UINT_8 *)"\0", 1); - - Update(finalcount, 8); // Cause a SHA1Transform() - - for(i = 0; i < 20; i++) - { - m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255); - } - - // Wipe variables for security reasons -#ifdef SHA1_WIPE_VARIABLES - i = 0; - memset(m_buffer, 0, 64); - memset(m_state, 0, 20); - memset(m_count, 0, 8); - memset(finalcount, 0, 8); - Transform(m_state, m_buffer); -#endif -} - -#ifdef SHA1_UTILITY_FUNCTIONS -// Get the final hash as a pre-formatted string -void CSHA1::ReportHash(char *szReport, unsigned char uReportType) -{ - unsigned char i; - char szTemp[16]; - - if(szReport == NULL) return; - - if(uReportType == REPORT_HEX) - { - sprintf(szTemp, "%02X", m_digest[0]); - strcat(szReport, szTemp); - - for(i = 1; i < 20; i++) - { - sprintf(szTemp, " %02X", m_digest[i]); - strcat(szReport, szTemp); - } - } - else if(uReportType == REPORT_DIGIT) - { - sprintf(szTemp, "%u", m_digest[0]); - strcat(szReport, szTemp); - - for(i = 1; i < 20; i++) - { - sprintf(szTemp, " %u", m_digest[i]); - strcat(szReport, szTemp); - } - } - else strcpy(szReport, "Error: Unknown report type!"); -} -#endif - -// Get the raw message digest -void CSHA1::GetHash(UINT_8 *puDest) -{ - memcpy(puDest, m_digest, 20); -} +/* + 100% free public domain implementation of the SHA-1 algorithm + by Dominik Reichl + Web: http://www.dominik-reichl.de/ + + Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches) + - You can set the endianness in your files, no need to modify the + header file of the CSHA1 class any more + - Aligned data support + - Made support/compilation of the utility functions (ReportHash + and HashFile) optional (useful, if bytes count, for example in + embedded environments) + + Version 1.5 - 2005-01-01 + - 64-bit compiler compatibility added + - Made variable wiping optional (define SHA1_WIPE_VARIABLES) + - Removed unnecessary variable initializations + - ROL32 improvement for the Microsoft compiler (using _rotl) + + ======== Test Vectors (from FIPS PUB 180-1) ======== + + SHA1("abc") = + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + + SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + + SHA1(A million repetitions of "a") = + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#include "SHA1.h" + +#ifdef SHA1_UTILITY_FUNCTIONS +#define SHA1_MAX_FILE_BUFFER 8000 +#endif + +// Rotate x bits to the left +#ifndef ROL32 +#ifdef _MSC_VER +#define ROL32(_val32, _nBits) _rotl(_val32, _nBits) +#else +#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits)))) +#endif +#endif + +#ifdef SHA1_LITTLE_ENDIAN +#define SHABLK0(i) (m_block->l[i] = \ + (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF)) +#else +#define SHABLK0(i) (m_block->l[i]) +#endif + +#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \ + ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1)) + +// SHA-1 rounds +#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } +#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } +#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); } +#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); } +#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); } + +CSHA1::CSHA1() +{ + m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace; + + Reset(); +} + +CSHA1::~CSHA1() +{ + Reset(); +} + +void CSHA1::Reset() +{ + // SHA1 initialization constants + m_state[0] = 0x67452301; + m_state[1] = 0xEFCDAB89; + m_state[2] = 0x98BADCFE; + m_state[3] = 0x10325476; + m_state[4] = 0xC3D2E1F0; + + m_count[0] = 0; + m_count[1] = 0; +} + +void CSHA1::Transform(UINT_32 *state, UINT_8 *buffer) +{ + // Copy state[] to working vars + UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; + + memcpy(m_block, buffer, 64); + + // 4 rounds of 20 operations each. Loop unrolled. + _R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3); + _R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7); + _R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11); + _R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15); + _R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19); + _R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23); + _R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27); + _R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31); + _R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35); + _R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39); + _R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43); + _R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47); + _R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51); + _R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55); + _R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59); + _R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63); + _R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67); + _R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71); + _R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75); + _R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79); + + // Add the working vars back into state + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + // Wipe variables +#ifdef SHA1_WIPE_VARIABLES + a = b = c = d = e = 0; +#endif +} + +// Use this function to hash in binary data and strings +void CSHA1::Update(UINT_8 *data, UINT_32 len) +{ + UINT_32 i, j; + + j = (m_count[0] >> 3) & 63; + + if((m_count[0] += len << 3) < (len << 3)) m_count[1]++; + + m_count[1] += (len >> 29); + + if((j + len) > 63) + { + i = 64 - j; + memcpy(&m_buffer[j], data, i); + Transform(m_state, m_buffer); + + for(; i + 63 < len; i += 64) Transform(m_state, &data[i]); + + j = 0; + } + else i = 0; + + memcpy(&m_buffer[j], &data[i], len - i); +} + +#ifdef SHA1_UTILITY_FUNCTIONS +// Hash in file contents +bool CSHA1::HashFile(char *szFileName) +{ + unsigned long ulFileSize, ulRest, ulBlocks; + unsigned long i; + UINT_8 uData[SHA1_MAX_FILE_BUFFER]; + FILE *fIn; + + if(szFileName == NULL) return false; + + fIn = fopen(szFileName, "rb"); + if(fIn == NULL) return false; + + fseek(fIn, 0, SEEK_END); + ulFileSize = (unsigned long)ftell(fIn); + fseek(fIn, 0, SEEK_SET); + + if(ulFileSize != 0) + { + ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER; + ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER; + } + else + { + ulBlocks = 0; + ulRest = 0; + } + + for(i = 0; i < ulBlocks; i++) + { + fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn); + Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER); + } + + if(ulRest != 0) + { + fread(uData, 1, ulRest, fIn); + Update((UINT_8 *)uData, ulRest); + } + + fclose(fIn); fIn = NULL; + return true; +} +#endif + +void CSHA1::Final() +{ + UINT_32 i; + UINT_8 finalcount[8]; + + for(i = 0; i < 8; i++) + finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)] + >> ((3 - (i & 3)) * 8) ) & 255); // Endian independent + + Update((UINT_8 *)"\200", 1); + + while ((m_count[0] & 504) != 448) + Update((UINT_8 *)"\0", 1); + + Update(finalcount, 8); // Cause a SHA1Transform() + + for(i = 0; i < 20; i++) + { + m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255); + } + + // Wipe variables for security reasons +#ifdef SHA1_WIPE_VARIABLES + i = 0; + memset(m_buffer, 0, 64); + memset(m_state, 0, 20); + memset(m_count, 0, 8); + memset(finalcount, 0, 8); + Transform(m_state, m_buffer); +#endif +} + +#ifdef SHA1_UTILITY_FUNCTIONS +// Get the final hash as a pre-formatted string +void CSHA1::ReportHash(char *szReport, unsigned char uReportType) +{ + unsigned char i; + char szTemp[16]; + + if(szReport == NULL) return; + + if(uReportType == REPORT_HEX) + { + sprintf(szTemp, "%02X", m_digest[0]); + strcat(szReport, szTemp); + + for(i = 1; i < 20; i++) + { + sprintf(szTemp, " %02X", m_digest[i]); + strcat(szReport, szTemp); + } + } + else if(uReportType == REPORT_DIGIT) + { + sprintf(szTemp, "%u", m_digest[0]); + strcat(szReport, szTemp); + + for(i = 1; i < 20; i++) + { + sprintf(szTemp, " %u", m_digest[i]); + strcat(szReport, szTemp); + } + } + else strcpy(szReport, "Error: Unknown report type!"); +} +#endif + +// Get the raw message digest +void CSHA1::GetHash(UINT_8 *puDest) +{ + memcpy(puDest, m_digest, 20); +} diff --git a/backends/twitter/libtwitcurl/SHA1.h b/backends/twitter/libtwitcurl/SHA1.h index e7ea00f342e709f4a182783df8d1388875011e65..a326911343e998d06c090fe1fb27fcad8c47e785 100644 --- a/backends/twitter/libtwitcurl/SHA1.h +++ b/backends/twitter/libtwitcurl/SHA1.h @@ -1,148 +1,148 @@ -/* - 100% free public domain implementation of the SHA-1 algorithm - by Dominik Reichl - Web: http://www.dominik-reichl.de/ - - Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches) - - You can set the endianness in your files, no need to modify the - header file of the CSHA1 class any more - - Aligned data support - - Made support/compilation of the utility functions (ReportHash - and HashFile) optional (useful, if bytes count, for example in - embedded environments) - - Version 1.5 - 2005-01-01 - - 64-bit compiler compatibility added - - Made variable wiping optional (define SHA1_WIPE_VARIABLES) - - Removed unnecessary variable initializations - - ROL32 improvement for the Microsoft compiler (using _rotl) - - ======== Test Vectors (from FIPS PUB 180-1) ======== - - SHA1("abc") = - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D - - SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 - - SHA1(A million repetitions of "a") = - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -#ifndef ___SHA1_HDR___ -#define ___SHA1_HDR___ - -#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS) -#define SHA1_UTILITY_FUNCTIONS -#endif - -#include // Needed for memset and memcpy - -#ifdef SHA1_UTILITY_FUNCTIONS -#include // Needed for file access and sprintf -#include // Needed for strcat and strcpy -#endif - -#ifdef _MSC_VER -#include -#endif - -// You can define the endian mode in your files, without modifying the SHA1 -// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN -// in your files, before including the SHA1.h header file. If you don't -// define anything, the class defaults to little endian. - -#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN) -#define SHA1_LITTLE_ENDIAN -#endif - -// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if -// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it -// defaults to wiping. - -#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES) -#define SHA1_WIPE_VARIABLES -#endif - -///////////////////////////////////////////////////////////////////////////// -// Define 8- and 32-bit variables - -#ifndef UINT_32 - -#ifdef _MSC_VER - -#define UINT_8 unsigned __int8 -#define UINT_32 unsigned __int32 - -#else - -#define UINT_8 unsigned char - -#if (ULONG_MAX == 0xFFFFFFFF) -#define UINT_32 unsigned long -#else -#define UINT_32 unsigned int -#endif - -#endif -#endif - -///////////////////////////////////////////////////////////////////////////// -// Declare SHA1 workspace - -typedef union -{ - UINT_8 c[64]; - UINT_32 l[16]; -} SHA1_WORKSPACE_BLOCK; - -class CSHA1 -{ -public: -#ifdef SHA1_UTILITY_FUNCTIONS - // Two different formats for ReportHash(...) - enum - { - REPORT_HEX = 0, - REPORT_DIGIT = 1 - }; -#endif - - // Constructor and Destructor - CSHA1(); - ~CSHA1(); - - UINT_32 m_state[5]; - UINT_32 m_count[2]; - UINT_32 __reserved1[1]; - UINT_8 m_buffer[64]; - UINT_8 m_digest[20]; - UINT_32 __reserved2[3]; - - void Reset(); - - // Update the hash value - void Update(UINT_8 *data, UINT_32 len); -#ifdef SHA1_UTILITY_FUNCTIONS - bool HashFile(char *szFileName); -#endif - - // Finalize hash and report - void Final(); - - // Report functions: as pre-formatted and raw data -#ifdef SHA1_UTILITY_FUNCTIONS - void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX); -#endif - void GetHash(UINT_8 *puDest); - -private: - // Private SHA-1 transformation - void Transform(UINT_32 *state, UINT_8 *buffer); - - // Member variables - UINT_8 m_workspace[64]; - SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above -}; - -#endif +/* + 100% free public domain implementation of the SHA-1 algorithm + by Dominik Reichl + Web: http://www.dominik-reichl.de/ + + Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches) + - You can set the endianness in your files, no need to modify the + header file of the CSHA1 class any more + - Aligned data support + - Made support/compilation of the utility functions (ReportHash + and HashFile) optional (useful, if bytes count, for example in + embedded environments) + + Version 1.5 - 2005-01-01 + - 64-bit compiler compatibility added + - Made variable wiping optional (define SHA1_WIPE_VARIABLES) + - Removed unnecessary variable initializations + - ROL32 improvement for the Microsoft compiler (using _rotl) + + ======== Test Vectors (from FIPS PUB 180-1) ======== + + SHA1("abc") = + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + + SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + + SHA1(A million repetitions of "a") = + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#ifndef ___SHA1_HDR___ +#define ___SHA1_HDR___ + +#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS) +#define SHA1_UTILITY_FUNCTIONS +#endif + +#include // Needed for memset and memcpy + +#ifdef SHA1_UTILITY_FUNCTIONS +#include // Needed for file access and sprintf +#include // Needed for strcat and strcpy +#endif + +#ifdef _MSC_VER +#include +#endif + +// You can define the endian mode in your files, without modifying the SHA1 +// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN +// in your files, before including the SHA1.h header file. If you don't +// define anything, the class defaults to little endian. + +#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN) +#define SHA1_LITTLE_ENDIAN +#endif + +// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if +// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it +// defaults to wiping. + +#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES) +#define SHA1_WIPE_VARIABLES +#endif + +///////////////////////////////////////////////////////////////////////////// +// Define 8- and 32-bit variables + +#ifndef UINT_32 + +#ifdef _MSC_VER + +#define UINT_8 unsigned __int8 +#define UINT_32 unsigned __int32 + +#else + +#define UINT_8 unsigned char + +#if (ULONG_MAX == 0xFFFFFFFF) +#define UINT_32 unsigned long +#else +#define UINT_32 unsigned int +#endif + +#endif +#endif + +///////////////////////////////////////////////////////////////////////////// +// Declare SHA1 workspace + +typedef union +{ + UINT_8 c[64]; + UINT_32 l[16]; +} SHA1_WORKSPACE_BLOCK; + +class CSHA1 +{ +public: +#ifdef SHA1_UTILITY_FUNCTIONS + // Two different formats for ReportHash(...) + enum + { + REPORT_HEX = 0, + REPORT_DIGIT = 1 + }; +#endif + + // Constructor and Destructor + CSHA1(); + ~CSHA1(); + + UINT_32 m_state[5]; + UINT_32 m_count[2]; + UINT_32 __reserved1[1]; + UINT_8 m_buffer[64]; + UINT_8 m_digest[20]; + UINT_32 __reserved2[3]; + + void Reset(); + + // Update the hash value + void Update(UINT_8 *data, UINT_32 len); +#ifdef SHA1_UTILITY_FUNCTIONS + bool HashFile(char *szFileName); +#endif + + // Finalize hash and report + void Final(); + + // Report functions: as pre-formatted and raw data +#ifdef SHA1_UTILITY_FUNCTIONS + void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX); +#endif + void GetHash(UINT_8 *puDest); + +private: + // Private SHA-1 transformation + void Transform(UINT_32 *state, UINT_8 *buffer); + + // Member variables + UINT_8 m_workspace[64]; + SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above +}; + +#endif diff --git a/backends/twitter/libtwitcurl/base64.cpp b/backends/twitter/libtwitcurl/base64.cpp index 089517940cb90c4b1f0a1af656f58029563846cc..50006d4f36e0b37d7c2aba3e2706dd427734dafb 100644 --- a/backends/twitter/libtwitcurl/base64.cpp +++ b/backends/twitter/libtwitcurl/base64.cpp @@ -1,123 +1,123 @@ -/* - base64.cpp and base64.h - - Copyright (C) 2004-2008 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch - -*/ - -#include "base64.h" -#include - -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - - -static inline bool is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; - - } - - return ret; - -} - -std::string base64_decode(std::string const& encoded_string) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::string ret; - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - ret += char_array_3[i]; - i = 0; - } - } - - if (i) { - for (j = i; j <4; j++) - char_array_4[j] = 0; - - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; - } - - return ret; +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +#include "base64.h" +#include + +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} + +std::string base64_decode(std::string const& encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; } \ No newline at end of file diff --git a/backends/twitter/libtwitcurl/base64.h b/backends/twitter/libtwitcurl/base64.h index 639e696c52d0cfd090acc44bf14bd56f8e3265fc..ceb13579ce1b8e5607923ae2bcfaa4775c7ecb1c 100644 --- a/backends/twitter/libtwitcurl/base64.h +++ b/backends/twitter/libtwitcurl/base64.h @@ -1,4 +1,4 @@ -#include - -std::string base64_encode(unsigned char const* , unsigned int len); +#include + +std::string base64_encode(unsigned char const* , unsigned int len); std::string base64_decode(std::string const& s); \ No newline at end of file diff --git a/backends/twitter/libtwitcurl/oauthlib.cpp b/backends/twitter/libtwitcurl/oauthlib.cpp index 00732766304c652d4ba74b47b3e95c4d3bf986b6..aed9e43c9665cd2db72a659d079984fa55b626ff 100644 --- a/backends/twitter/libtwitcurl/oauthlib.cpp +++ b/backends/twitter/libtwitcurl/oauthlib.cpp @@ -1,681 +1,681 @@ -#include "twitcurlurls.h" -#include "oauthlib.h" -#include "HMAC_SHA1.h" -#include "base64.h" -#include "urlencode.h" - -/*++ -* @method: oAuth::oAuth -* -* @description: constructor -* -* @input: none -* -* @output: none -* -*--*/ -oAuth::oAuth() -{ -} - -/*++ -* @method: oAuth::~oAuth -* -* @description: destructor -* -* @input: none -* -* @output: none -* -*--*/ -oAuth::~oAuth() -{ -} - -/*++ -* @method: oAuth::clone -* -* @description: creates a clone of oAuth object -* -* @input: none -* -* @output: cloned oAuth object -* -*--*/ -oAuth oAuth::clone() -{ - oAuth cloneObj; - cloneObj.m_consumerKey = m_consumerKey; - cloneObj.m_consumerSecret = m_consumerSecret; - cloneObj.m_oAuthTokenKey = m_oAuthTokenKey; - cloneObj.m_oAuthTokenSecret = m_oAuthTokenSecret; - cloneObj.m_oAuthPin = m_oAuthPin; - cloneObj.m_nonce = m_nonce; - cloneObj.m_timeStamp = m_timeStamp; - cloneObj.m_oAuthScreenName = m_oAuthScreenName; - return cloneObj; -} - - -/*++ -* @method: oAuth::getConsumerKey -* -* @description: this method gives consumer key that is being used currently -* -* @input: none -* -* @output: consumer key -* -*--*/ -void oAuth::getConsumerKey( std::string& consumerKey ) -{ - consumerKey = m_consumerKey; -} - -/*++ -* @method: oAuth::setConsumerKey -* -* @description: this method saves consumer key that should be used -* -* @input: consumer key -* -* @output: none -* -*--*/ -void oAuth::setConsumerKey( const std::string& consumerKey ) -{ - m_consumerKey.assign( consumerKey ); -} - -/*++ -* @method: oAuth::getConsumerSecret -* -* @description: this method gives consumer secret that is being used currently -* -* @input: none -* -* @output: consumer secret -* -*--*/ -void oAuth::getConsumerSecret( std::string& consumerSecret ) -{ - consumerSecret = m_consumerSecret; -} - -/*++ -* @method: oAuth::setConsumerSecret -* -* @description: this method saves consumer secret that should be used -* -* @input: consumer secret -* -* @output: none -* -*--*/ -void oAuth::setConsumerSecret( const std::string& consumerSecret ) -{ - m_consumerSecret = consumerSecret; -} - -/*++ -* @method: oAuth::getOAuthTokenKey -* -* @description: this method gives OAuth token (also called access token) that is being used currently -* -* @input: none -* -* @output: OAuth token -* -*--*/ -void oAuth::getOAuthTokenKey( std::string& oAuthTokenKey ) -{ - oAuthTokenKey = m_oAuthTokenKey; -} - -/*++ -* @method: oAuth::setOAuthTokenKey -* -* @description: this method saves OAuth token that should be used -* -* @input: OAuth token -* -* @output: none -* -*--*/ -void oAuth::setOAuthTokenKey( const std::string& oAuthTokenKey ) -{ - m_oAuthTokenKey = oAuthTokenKey; -} - -/*++ -* @method: oAuth::getOAuthTokenSecret -* -* @description: this method gives OAuth token secret that is being used currently -* -* @input: none -* -* @output: OAuth token secret -* -*--*/ -void oAuth::getOAuthTokenSecret( std::string& oAuthTokenSecret ) -{ - oAuthTokenSecret = m_oAuthTokenSecret; -} - -/*++ -* @method: oAuth::setOAuthTokenSecret -* -* @description: this method saves OAuth token that should be used -* -* @input: OAuth token secret -* -* @output: none -* -*--*/ -void oAuth::setOAuthTokenSecret( const std::string& oAuthTokenSecret ) -{ - m_oAuthTokenSecret = oAuthTokenSecret; -} - -/*++ -* @method: oAuth::getOAuthScreenName -* -* @description: this method gives authorized user's screenname -* -* @input: none -* -* @output: screen name -* -*--*/ -void oAuth::getOAuthScreenName( std::string& oAuthScreenName ) -{ - oAuthScreenName = m_oAuthScreenName; -} - -/*++ -* @method: oAuth::setOAuthScreenName -* -* @description: this method sets authorized user's screenname -* -* @input: screen name -* -* @output: none -* -*--*/ -void oAuth::setOAuthScreenName( const std::string& oAuthScreenName ) -{ - m_oAuthScreenName = oAuthScreenName; -} - -/*++ -* @method: oAuth::getOAuthPin -* -* @description: this method gives OAuth verifier PIN -* -* @input: none -* -* @output: OAuth verifier PIN -* -*--*/ -void oAuth::getOAuthPin( std::string& oAuthPin ) -{ - oAuthPin = m_oAuthPin; -} - -/*++ -* @method: oAuth::setOAuthPin -* -* @description: this method sets OAuth verifier PIN -* -* @input: OAuth verifier PIN -* -* @output: none -* -*--*/ -void oAuth::setOAuthPin( const std::string& oAuthPin ) -{ - m_oAuthPin = oAuthPin; -} - -/*++ -* @method: oAuth::generateNonceTimeStamp -* -* @description: this method generates nonce and timestamp for OAuth header -* -* @input: none -* -* @output: none -* -* @remarks: internal method -* -*--*/ -void oAuth::generateNonceTimeStamp() -{ - char szTime[oAuthLibDefaults::OAUTHLIB_BUFFSIZE]; - char szRand[oAuthLibDefaults::OAUTHLIB_BUFFSIZE]; - memset( szTime, 0, oAuthLibDefaults::OAUTHLIB_BUFFSIZE ); - memset( szRand, 0, oAuthLibDefaults::OAUTHLIB_BUFFSIZE ); - srand( (unsigned int)time( NULL ) ); - sprintf( szRand, "%x", rand()%1000 ); - sprintf( szTime, "%ld", time( NULL ) ); - - m_nonce.assign( szTime ); - m_nonce.append( szRand ); - m_timeStamp.assign( szTime ); -} - -/*++ -* @method: oAuth::buildOAuthRawDataKeyValPairs -* -* @description: this method prepares key-value pairs from the data part of the URL -* or from the URL post fields data, as required by OAuth header -* and signature generation. -* -* @input: rawData - Raw data either from the URL itself or from post fields. -* Should already be url encoded. -* urlencodeData - If true, string will be urlencoded before converting -* to key value pairs. -* -* @output: rawDataKeyValuePairs - Map in which key-value pairs are populated -* -* @remarks: internal method -* -*--*/ -void oAuth::buildOAuthRawDataKeyValPairs( const std::string& rawData, - bool urlencodeData, - oAuthKeyValuePairs& rawDataKeyValuePairs ) -{ - /* Raw data if it's present. Data should already be urlencoded once */ - if( rawData.empty() ) - { - return; - } - - size_t nSep = std::string::npos; - size_t nPos = std::string::npos; - std::string dataKeyVal; - std::string dataKey; - std::string dataVal; - - /* This raw data part can contain many key value pairs: key1=value1&key2=value2&key3=value3 */ - std::string dataPart = rawData; - while( std::string::npos != ( nSep = dataPart.find_first_of("&") ) ) - { - /* Extract first key=value pair */ - dataKeyVal = dataPart.substr( 0, nSep ); - - /* Split them */ - nPos = dataKeyVal.find_first_of( "=" ); - if( std::string::npos != nPos ) - { - dataKey = dataKeyVal.substr( 0, nPos ); - dataVal = dataKeyVal.substr( nPos + 1 ); - - /* Put this key=value pair in map */ - rawDataKeyValuePairs[dataKey] = urlencodeData ? urlencode( dataVal ) : dataVal; - } - dataPart = dataPart.substr( nSep + 1 ); - } - - /* For the last key=value */ - dataKeyVal = dataPart.substr( 0, nSep ); - - /* Split them */ - nPos = dataKeyVal.find_first_of( "=" ); - if( std::string::npos != nPos ) - { - dataKey = dataKeyVal.substr( 0, nPos ); - dataVal = dataKeyVal.substr( nPos + 1 ); - - /* Put this key=value pair in map */ - rawDataKeyValuePairs[dataKey] = urlencodeData ? urlencode( dataVal ) : dataVal; - } -} - -/*++ -* @method: oAuth::buildOAuthTokenKeyValuePairs -* -* @description: this method prepares key-value pairs required for OAuth header -* and signature generation. -* -* @input: includeOAuthVerifierPin - flag to indicate whether oauth_verifer key-value -* pair needs to be included. oauth_verifer is only -* used during exchanging request token with access token. -* oauthSignature - base64 and url encoded OAuth signature. -* generateTimestamp - If true, then generate new timestamp for nonce. -* -* @output: keyValueMap - map in which key-value pairs are populated -* -* @remarks: internal method -* -*--*/ -bool oAuth::buildOAuthTokenKeyValuePairs( const bool includeOAuthVerifierPin, - const std::string& oauthSignature, - oAuthKeyValuePairs& keyValueMap, - const bool generateTimestamp ) -{ - /* Generate nonce and timestamp if required */ - if( generateTimestamp ) - { - generateNonceTimeStamp(); - } - - /* Consumer key and its value */ - keyValueMap[oAuthLibDefaults::OAUTHLIB_CONSUMERKEY_KEY] = m_consumerKey; - - /* Nonce key and its value */ - keyValueMap[oAuthLibDefaults::OAUTHLIB_NONCE_KEY] = m_nonce; - - /* Signature if supplied */ - if( oauthSignature.length() ) - { - keyValueMap[oAuthLibDefaults::OAUTHLIB_SIGNATURE_KEY] = oauthSignature; - } - - /* Signature method, only HMAC-SHA1 as of now */ - keyValueMap[oAuthLibDefaults::OAUTHLIB_SIGNATUREMETHOD_KEY] = std::string( "HMAC-SHA1" ); - - /* Timestamp */ - keyValueMap[oAuthLibDefaults::OAUTHLIB_TIMESTAMP_KEY] = m_timeStamp; - - /* Token */ - if( m_oAuthTokenKey.length() ) - { - keyValueMap[oAuthLibDefaults::OAUTHLIB_TOKEN_KEY] = m_oAuthTokenKey; - } - - /* Verifier */ - if( includeOAuthVerifierPin && m_oAuthPin.length() ) - { - keyValueMap[oAuthLibDefaults::OAUTHLIB_VERIFIER_KEY] = m_oAuthPin; - } - - /* Version */ - keyValueMap[oAuthLibDefaults::OAUTHLIB_VERSION_KEY] = std::string( "1.0" ); - - return !keyValueMap.empty(); -} - -/*++ -* @method: oAuth::getSignature -* -* @description: this method calculates HMAC-SHA1 signature of OAuth header -* -* @input: eType - HTTP request type -* rawUrl - raw url of the HTTP request -* rawKeyValuePairs - key-value pairs containing OAuth headers and HTTP data -* -* @output: oAuthSignature - base64 and url encoded signature -* -* @remarks: internal method -* -*--*/ -bool oAuth::getSignature( const eOAuthHttpRequestType eType, - const std::string& rawUrl, - const oAuthKeyValuePairs& rawKeyValuePairs, - std::string& oAuthSignature ) -{ - std::string rawParams; - std::string paramsSeperator; - std::string sigBase; - - /* Initially empty signature */ - oAuthSignature = ""; - - /* Build a string using key-value pairs */ - paramsSeperator = "&"; - getStringFromOAuthKeyValuePairs( rawKeyValuePairs, rawParams, paramsSeperator ); - - /* Start constructing base signature string. Refer http://dev.twitter.com/auth#intro */ - switch( eType ) - { - case eOAuthHttpGet: - { - sigBase.assign( "GET&" ); - } - break; - - case eOAuthHttpPost: - { - sigBase.assign( "POST&" ); - } - break; - - case eOAuthHttpDelete: - { - sigBase.assign( "DELETE&" ); - } - break; - - default: - { - return false; - } - break; - } - sigBase.append( urlencode( rawUrl ) ); - sigBase.append( "&" ); - sigBase.append( urlencode( rawParams ) ); - - /* Now, hash the signature base string using HMAC_SHA1 class */ - CHMAC_SHA1 objHMACSHA1; - std::string secretSigningKey; - unsigned char strDigest[oAuthLibDefaults::OAUTHLIB_BUFFSIZE_LARGE]; - - memset( strDigest, 0, oAuthLibDefaults::OAUTHLIB_BUFFSIZE_LARGE ); - - /* Signing key is composed of consumer_secret&token_secret */ - secretSigningKey.assign( m_consumerSecret ); - secretSigningKey.append( "&" ); - if( m_oAuthTokenSecret.length() ) - { - secretSigningKey.append( m_oAuthTokenSecret ); - } - - objHMACSHA1.HMAC_SHA1( (unsigned char*)sigBase.c_str(), - sigBase.length(), - (unsigned char*)secretSigningKey.c_str(), - secretSigningKey.length(), - strDigest ); - - /* Do a base64 encode of signature */ - std::string base64Str = base64_encode( strDigest, 20 /* SHA 1 digest is 160 bits */ ); - - /* Do an url encode */ - oAuthSignature = urlencode( base64Str ); - - return !oAuthSignature.empty(); -} - -/*++ -* @method: oAuth::getOAuthHeader -* -* @description: this method builds OAuth header that should be used in HTTP requests to twitter -* -* @input: eType - HTTP request type -* rawUrl - raw url of the HTTP request -* rawData - HTTP data (post fields) -* includeOAuthVerifierPin - flag to indicate whether or not oauth_verifier needs to included -* in OAuth header -* -* @output: oAuthHttpHeader - OAuth header -* -*--*/ -bool oAuth::getOAuthHeader( const eOAuthHttpRequestType eType, - const std::string& rawUrl, - const std::string& rawData, - std::string& oAuthHttpHeader, - const bool includeOAuthVerifierPin ) -{ - oAuthKeyValuePairs rawKeyValuePairs; - std::string rawParams; - std::string oauthSignature; - std::string paramsSeperator; - std::string pureUrl( rawUrl ); - - /* Clear header string initially */ - oAuthHttpHeader = ""; - rawKeyValuePairs.clear(); - - /* If URL itself contains ?key=value, then extract and put them in map */ - size_t nPos = rawUrl.find_first_of( "?" ); - if( std::string::npos != nPos ) - { - /* Get only URL */ - pureUrl = rawUrl.substr( 0, nPos ); - - /* Get only key=value data part */ - std::string dataPart = rawUrl.substr( nPos + 1 ); - - /* Split the data in URL as key=value pairs */ - buildOAuthRawDataKeyValPairs( dataPart, true, rawKeyValuePairs ); - } - - /* Split the raw data if it's present, as key=value pairs. Data should already be urlencoded once */ - buildOAuthRawDataKeyValPairs( rawData, false, rawKeyValuePairs ); - - /* Build key-value pairs needed for OAuth request token, without signature */ - buildOAuthTokenKeyValuePairs( includeOAuthVerifierPin, std::string( "" ), rawKeyValuePairs, true ); - - /* Get url encoded base64 signature using request type, url and parameters */ - getSignature( eType, pureUrl, rawKeyValuePairs, oauthSignature ); - - /* Clear map so that the parameters themselves are not sent along with the OAuth values */ - rawKeyValuePairs.clear(); - - /* Now, again build key-value pairs with signature this time */ - buildOAuthTokenKeyValuePairs( includeOAuthVerifierPin, oauthSignature, rawKeyValuePairs, false ); - - /* Get OAuth header in string format */ - paramsSeperator = ","; - getStringFromOAuthKeyValuePairs( rawKeyValuePairs, rawParams, paramsSeperator ); - - /* Build authorization header */ - oAuthHttpHeader.assign( oAuthLibDefaults::OAUTHLIB_AUTHHEADER_STRING ); - oAuthHttpHeader.append( rawParams ); - - return !oAuthHttpHeader.empty(); -} - -/*++ -* @method: oAuth::getStringFromOAuthKeyValuePairs -* -* @description: this method builds a sorted string from key-value pairs -* -* @input: rawParamMap - key-value pairs map -* paramsSeperator - sepearator, either & or , -* -* @output: rawParams - sorted string of OAuth parameters -* -* @remarks: internal method -* -*--*/ -bool oAuth::getStringFromOAuthKeyValuePairs( const oAuthKeyValuePairs& rawParamMap, - std::string& rawParams, - const std::string& paramsSeperator ) -{ - rawParams = ""; - if( rawParamMap.empty() ) - { - return false; - } - - oAuthKeyValueList keyValueList; - std::string dummyStr; - - /* Push key-value pairs to a list of strings */ - keyValueList.clear(); - oAuthKeyValuePairs::const_iterator itMap = rawParamMap.begin(); - for( ; itMap != rawParamMap.end(); itMap++ ) - { - dummyStr.assign( itMap->first ); - dummyStr.append( "=" ); - if( paramsSeperator == "," ) - { - dummyStr.append( "\"" ); - } - dummyStr.append( itMap->second ); - if( paramsSeperator == "," ) - { - dummyStr.append( "\"" ); - } - keyValueList.push_back( dummyStr ); - } - - /* Sort key-value pairs based on key name */ - keyValueList.sort(); - - /* Now, form a string */ - dummyStr = ""; - oAuthKeyValueList::iterator itKeyValue = keyValueList.begin(); - for( ; itKeyValue != keyValueList.end(); itKeyValue++ ) - { - if( dummyStr.length() ) - { - dummyStr.append( paramsSeperator ); - } - dummyStr.append( itKeyValue->c_str() ); - } - rawParams = dummyStr; - return !rawParams.empty(); -} - -/*++ -* @method: oAuth::extractOAuthTokenKeySecret -* -* @description: this method extracts oauth token key and secret from -* twitter's HTTP response -* -* @input: requestTokenResponse - response from twitter -* -* @output: none -* -*--*/ -bool oAuth::extractOAuthTokenKeySecret( const std::string& requestTokenResponse ) -{ - if( requestTokenResponse.empty() ) - { - return false; - } - - size_t nPos = std::string::npos; - std::string strDummy; - - /* Get oauth_token key */ - nPos = requestTokenResponse.find( oAuthLibDefaults::OAUTHLIB_TOKEN_KEY ); - if( std::string::npos != nPos ) - { - nPos = nPos + oAuthLibDefaults::OAUTHLIB_TOKEN_KEY.length() + strlen( "=" ); - strDummy = requestTokenResponse.substr( nPos ); - nPos = strDummy.find( "&" ); - if( std::string::npos != nPos ) - { - m_oAuthTokenKey = strDummy.substr( 0, nPos ); - } - } - - /* Get oauth_token_secret */ - nPos = requestTokenResponse.find( oAuthLibDefaults::OAUTHLIB_TOKENSECRET_KEY ); - if( std::string::npos != nPos ) - { - nPos = nPos + oAuthLibDefaults::OAUTHLIB_TOKENSECRET_KEY.length() + strlen( "=" ); - strDummy = requestTokenResponse.substr( nPos ); - nPos = strDummy.find( "&" ); - if( std::string::npos != nPos ) - { - m_oAuthTokenSecret = strDummy.substr( 0, nPos ); - } - } - - /* Get screen_name */ - nPos = requestTokenResponse.find( oAuthLibDefaults::OAUTHLIB_SCREENNAME_KEY ); - if( std::string::npos != nPos ) - { - nPos = nPos + oAuthLibDefaults::OAUTHLIB_SCREENNAME_KEY.length() + strlen( "=" ); - strDummy = requestTokenResponse.substr( nPos ); - m_oAuthScreenName = strDummy; - } - - return true; -} - +#include "twitcurlurls.h" +#include "oauthlib.h" +#include "HMAC_SHA1.h" +#include "base64.h" +#include "urlencode.h" + +/*++ +* @method: oAuth::oAuth +* +* @description: constructor +* +* @input: none +* +* @output: none +* +*--*/ +oAuth::oAuth() +{ +} + +/*++ +* @method: oAuth::~oAuth +* +* @description: destructor +* +* @input: none +* +* @output: none +* +*--*/ +oAuth::~oAuth() +{ +} + +/*++ +* @method: oAuth::clone +* +* @description: creates a clone of oAuth object +* +* @input: none +* +* @output: cloned oAuth object +* +*--*/ +oAuth oAuth::clone() +{ + oAuth cloneObj; + cloneObj.m_consumerKey = m_consumerKey; + cloneObj.m_consumerSecret = m_consumerSecret; + cloneObj.m_oAuthTokenKey = m_oAuthTokenKey; + cloneObj.m_oAuthTokenSecret = m_oAuthTokenSecret; + cloneObj.m_oAuthPin = m_oAuthPin; + cloneObj.m_nonce = m_nonce; + cloneObj.m_timeStamp = m_timeStamp; + cloneObj.m_oAuthScreenName = m_oAuthScreenName; + return cloneObj; +} + + +/*++ +* @method: oAuth::getConsumerKey +* +* @description: this method gives consumer key that is being used currently +* +* @input: none +* +* @output: consumer key +* +*--*/ +void oAuth::getConsumerKey( std::string& consumerKey ) +{ + consumerKey = m_consumerKey; +} + +/*++ +* @method: oAuth::setConsumerKey +* +* @description: this method saves consumer key that should be used +* +* @input: consumer key +* +* @output: none +* +*--*/ +void oAuth::setConsumerKey( const std::string& consumerKey ) +{ + m_consumerKey.assign( consumerKey ); +} + +/*++ +* @method: oAuth::getConsumerSecret +* +* @description: this method gives consumer secret that is being used currently +* +* @input: none +* +* @output: consumer secret +* +*--*/ +void oAuth::getConsumerSecret( std::string& consumerSecret ) +{ + consumerSecret = m_consumerSecret; +} + +/*++ +* @method: oAuth::setConsumerSecret +* +* @description: this method saves consumer secret that should be used +* +* @input: consumer secret +* +* @output: none +* +*--*/ +void oAuth::setConsumerSecret( const std::string& consumerSecret ) +{ + m_consumerSecret = consumerSecret; +} + +/*++ +* @method: oAuth::getOAuthTokenKey +* +* @description: this method gives OAuth token (also called access token) that is being used currently +* +* @input: none +* +* @output: OAuth token +* +*--*/ +void oAuth::getOAuthTokenKey( std::string& oAuthTokenKey ) +{ + oAuthTokenKey = m_oAuthTokenKey; +} + +/*++ +* @method: oAuth::setOAuthTokenKey +* +* @description: this method saves OAuth token that should be used +* +* @input: OAuth token +* +* @output: none +* +*--*/ +void oAuth::setOAuthTokenKey( const std::string& oAuthTokenKey ) +{ + m_oAuthTokenKey = oAuthTokenKey; +} + +/*++ +* @method: oAuth::getOAuthTokenSecret +* +* @description: this method gives OAuth token secret that is being used currently +* +* @input: none +* +* @output: OAuth token secret +* +*--*/ +void oAuth::getOAuthTokenSecret( std::string& oAuthTokenSecret ) +{ + oAuthTokenSecret = m_oAuthTokenSecret; +} + +/*++ +* @method: oAuth::setOAuthTokenSecret +* +* @description: this method saves OAuth token that should be used +* +* @input: OAuth token secret +* +* @output: none +* +*--*/ +void oAuth::setOAuthTokenSecret( const std::string& oAuthTokenSecret ) +{ + m_oAuthTokenSecret = oAuthTokenSecret; +} + +/*++ +* @method: oAuth::getOAuthScreenName +* +* @description: this method gives authorized user's screenname +* +* @input: none +* +* @output: screen name +* +*--*/ +void oAuth::getOAuthScreenName( std::string& oAuthScreenName ) +{ + oAuthScreenName = m_oAuthScreenName; +} + +/*++ +* @method: oAuth::setOAuthScreenName +* +* @description: this method sets authorized user's screenname +* +* @input: screen name +* +* @output: none +* +*--*/ +void oAuth::setOAuthScreenName( const std::string& oAuthScreenName ) +{ + m_oAuthScreenName = oAuthScreenName; +} + +/*++ +* @method: oAuth::getOAuthPin +* +* @description: this method gives OAuth verifier PIN +* +* @input: none +* +* @output: OAuth verifier PIN +* +*--*/ +void oAuth::getOAuthPin( std::string& oAuthPin ) +{ + oAuthPin = m_oAuthPin; +} + +/*++ +* @method: oAuth::setOAuthPin +* +* @description: this method sets OAuth verifier PIN +* +* @input: OAuth verifier PIN +* +* @output: none +* +*--*/ +void oAuth::setOAuthPin( const std::string& oAuthPin ) +{ + m_oAuthPin = oAuthPin; +} + +/*++ +* @method: oAuth::generateNonceTimeStamp +* +* @description: this method generates nonce and timestamp for OAuth header +* +* @input: none +* +* @output: none +* +* @remarks: internal method +* +*--*/ +void oAuth::generateNonceTimeStamp() +{ + char szTime[oAuthLibDefaults::OAUTHLIB_BUFFSIZE]; + char szRand[oAuthLibDefaults::OAUTHLIB_BUFFSIZE]; + memset( szTime, 0, oAuthLibDefaults::OAUTHLIB_BUFFSIZE ); + memset( szRand, 0, oAuthLibDefaults::OAUTHLIB_BUFFSIZE ); + srand( (unsigned int)time( NULL ) ); + sprintf( szRand, "%x", rand()%1000 ); + sprintf( szTime, "%ld", time( NULL ) ); + + m_nonce.assign( szTime ); + m_nonce.append( szRand ); + m_timeStamp.assign( szTime ); +} + +/*++ +* @method: oAuth::buildOAuthRawDataKeyValPairs +* +* @description: this method prepares key-value pairs from the data part of the URL +* or from the URL post fields data, as required by OAuth header +* and signature generation. +* +* @input: rawData - Raw data either from the URL itself or from post fields. +* Should already be url encoded. +* urlencodeData - If true, string will be urlencoded before converting +* to key value pairs. +* +* @output: rawDataKeyValuePairs - Map in which key-value pairs are populated +* +* @remarks: internal method +* +*--*/ +void oAuth::buildOAuthRawDataKeyValPairs( const std::string& rawData, + bool urlencodeData, + oAuthKeyValuePairs& rawDataKeyValuePairs ) +{ + /* Raw data if it's present. Data should already be urlencoded once */ + if( rawData.empty() ) + { + return; + } + + size_t nSep = std::string::npos; + size_t nPos = std::string::npos; + std::string dataKeyVal; + std::string dataKey; + std::string dataVal; + + /* This raw data part can contain many key value pairs: key1=value1&key2=value2&key3=value3 */ + std::string dataPart = rawData; + while( std::string::npos != ( nSep = dataPart.find_first_of("&") ) ) + { + /* Extract first key=value pair */ + dataKeyVal = dataPart.substr( 0, nSep ); + + /* Split them */ + nPos = dataKeyVal.find_first_of( "=" ); + if( std::string::npos != nPos ) + { + dataKey = dataKeyVal.substr( 0, nPos ); + dataVal = dataKeyVal.substr( nPos + 1 ); + + /* Put this key=value pair in map */ + rawDataKeyValuePairs[dataKey] = urlencodeData ? urlencode( dataVal ) : dataVal; + } + dataPart = dataPart.substr( nSep + 1 ); + } + + /* For the last key=value */ + dataKeyVal = dataPart.substr( 0, nSep ); + + /* Split them */ + nPos = dataKeyVal.find_first_of( "=" ); + if( std::string::npos != nPos ) + { + dataKey = dataKeyVal.substr( 0, nPos ); + dataVal = dataKeyVal.substr( nPos + 1 ); + + /* Put this key=value pair in map */ + rawDataKeyValuePairs[dataKey] = urlencodeData ? urlencode( dataVal ) : dataVal; + } +} + +/*++ +* @method: oAuth::buildOAuthTokenKeyValuePairs +* +* @description: this method prepares key-value pairs required for OAuth header +* and signature generation. +* +* @input: includeOAuthVerifierPin - flag to indicate whether oauth_verifer key-value +* pair needs to be included. oauth_verifer is only +* used during exchanging request token with access token. +* oauthSignature - base64 and url encoded OAuth signature. +* generateTimestamp - If true, then generate new timestamp for nonce. +* +* @output: keyValueMap - map in which key-value pairs are populated +* +* @remarks: internal method +* +*--*/ +bool oAuth::buildOAuthTokenKeyValuePairs( const bool includeOAuthVerifierPin, + const std::string& oauthSignature, + oAuthKeyValuePairs& keyValueMap, + const bool generateTimestamp ) +{ + /* Generate nonce and timestamp if required */ + if( generateTimestamp ) + { + generateNonceTimeStamp(); + } + + /* Consumer key and its value */ + keyValueMap[oAuthLibDefaults::OAUTHLIB_CONSUMERKEY_KEY] = m_consumerKey; + + /* Nonce key and its value */ + keyValueMap[oAuthLibDefaults::OAUTHLIB_NONCE_KEY] = m_nonce; + + /* Signature if supplied */ + if( oauthSignature.length() ) + { + keyValueMap[oAuthLibDefaults::OAUTHLIB_SIGNATURE_KEY] = oauthSignature; + } + + /* Signature method, only HMAC-SHA1 as of now */ + keyValueMap[oAuthLibDefaults::OAUTHLIB_SIGNATUREMETHOD_KEY] = std::string( "HMAC-SHA1" ); + + /* Timestamp */ + keyValueMap[oAuthLibDefaults::OAUTHLIB_TIMESTAMP_KEY] = m_timeStamp; + + /* Token */ + if( m_oAuthTokenKey.length() ) + { + keyValueMap[oAuthLibDefaults::OAUTHLIB_TOKEN_KEY] = m_oAuthTokenKey; + } + + /* Verifier */ + if( includeOAuthVerifierPin && m_oAuthPin.length() ) + { + keyValueMap[oAuthLibDefaults::OAUTHLIB_VERIFIER_KEY] = m_oAuthPin; + } + + /* Version */ + keyValueMap[oAuthLibDefaults::OAUTHLIB_VERSION_KEY] = std::string( "1.0" ); + + return !keyValueMap.empty(); +} + +/*++ +* @method: oAuth::getSignature +* +* @description: this method calculates HMAC-SHA1 signature of OAuth header +* +* @input: eType - HTTP request type +* rawUrl - raw url of the HTTP request +* rawKeyValuePairs - key-value pairs containing OAuth headers and HTTP data +* +* @output: oAuthSignature - base64 and url encoded signature +* +* @remarks: internal method +* +*--*/ +bool oAuth::getSignature( const eOAuthHttpRequestType eType, + const std::string& rawUrl, + const oAuthKeyValuePairs& rawKeyValuePairs, + std::string& oAuthSignature ) +{ + std::string rawParams; + std::string paramsSeperator; + std::string sigBase; + + /* Initially empty signature */ + oAuthSignature = ""; + + /* Build a string using key-value pairs */ + paramsSeperator = "&"; + getStringFromOAuthKeyValuePairs( rawKeyValuePairs, rawParams, paramsSeperator ); + + /* Start constructing base signature string. Refer http://dev.twitter.com/auth#intro */ + switch( eType ) + { + case eOAuthHttpGet: + { + sigBase.assign( "GET&" ); + } + break; + + case eOAuthHttpPost: + { + sigBase.assign( "POST&" ); + } + break; + + case eOAuthHttpDelete: + { + sigBase.assign( "DELETE&" ); + } + break; + + default: + { + return false; + } + break; + } + sigBase.append( urlencode( rawUrl ) ); + sigBase.append( "&" ); + sigBase.append( urlencode( rawParams ) ); + + /* Now, hash the signature base string using HMAC_SHA1 class */ + CHMAC_SHA1 objHMACSHA1; + std::string secretSigningKey; + unsigned char strDigest[oAuthLibDefaults::OAUTHLIB_BUFFSIZE_LARGE]; + + memset( strDigest, 0, oAuthLibDefaults::OAUTHLIB_BUFFSIZE_LARGE ); + + /* Signing key is composed of consumer_secret&token_secret */ + secretSigningKey.assign( m_consumerSecret ); + secretSigningKey.append( "&" ); + if( m_oAuthTokenSecret.length() ) + { + secretSigningKey.append( m_oAuthTokenSecret ); + } + + objHMACSHA1.HMAC_SHA1( (unsigned char*)sigBase.c_str(), + sigBase.length(), + (unsigned char*)secretSigningKey.c_str(), + secretSigningKey.length(), + strDigest ); + + /* Do a base64 encode of signature */ + std::string base64Str = base64_encode( strDigest, 20 /* SHA 1 digest is 160 bits */ ); + + /* Do an url encode */ + oAuthSignature = urlencode( base64Str ); + + return !oAuthSignature.empty(); +} + +/*++ +* @method: oAuth::getOAuthHeader +* +* @description: this method builds OAuth header that should be used in HTTP requests to twitter +* +* @input: eType - HTTP request type +* rawUrl - raw url of the HTTP request +* rawData - HTTP data (post fields) +* includeOAuthVerifierPin - flag to indicate whether or not oauth_verifier needs to included +* in OAuth header +* +* @output: oAuthHttpHeader - OAuth header +* +*--*/ +bool oAuth::getOAuthHeader( const eOAuthHttpRequestType eType, + const std::string& rawUrl, + const std::string& rawData, + std::string& oAuthHttpHeader, + const bool includeOAuthVerifierPin ) +{ + oAuthKeyValuePairs rawKeyValuePairs; + std::string rawParams; + std::string oauthSignature; + std::string paramsSeperator; + std::string pureUrl( rawUrl ); + + /* Clear header string initially */ + oAuthHttpHeader = ""; + rawKeyValuePairs.clear(); + + /* If URL itself contains ?key=value, then extract and put them in map */ + size_t nPos = rawUrl.find_first_of( "?" ); + if( std::string::npos != nPos ) + { + /* Get only URL */ + pureUrl = rawUrl.substr( 0, nPos ); + + /* Get only key=value data part */ + std::string dataPart = rawUrl.substr( nPos + 1 ); + + /* Split the data in URL as key=value pairs */ + buildOAuthRawDataKeyValPairs( dataPart, true, rawKeyValuePairs ); + } + + /* Split the raw data if it's present, as key=value pairs. Data should already be urlencoded once */ + buildOAuthRawDataKeyValPairs( rawData, false, rawKeyValuePairs ); + + /* Build key-value pairs needed for OAuth request token, without signature */ + buildOAuthTokenKeyValuePairs( includeOAuthVerifierPin, std::string( "" ), rawKeyValuePairs, true ); + + /* Get url encoded base64 signature using request type, url and parameters */ + getSignature( eType, pureUrl, rawKeyValuePairs, oauthSignature ); + + /* Clear map so that the parameters themselves are not sent along with the OAuth values */ + rawKeyValuePairs.clear(); + + /* Now, again build key-value pairs with signature this time */ + buildOAuthTokenKeyValuePairs( includeOAuthVerifierPin, oauthSignature, rawKeyValuePairs, false ); + + /* Get OAuth header in string format */ + paramsSeperator = ","; + getStringFromOAuthKeyValuePairs( rawKeyValuePairs, rawParams, paramsSeperator ); + + /* Build authorization header */ + oAuthHttpHeader.assign( oAuthLibDefaults::OAUTHLIB_AUTHHEADER_STRING ); + oAuthHttpHeader.append( rawParams ); + + return !oAuthHttpHeader.empty(); +} + +/*++ +* @method: oAuth::getStringFromOAuthKeyValuePairs +* +* @description: this method builds a sorted string from key-value pairs +* +* @input: rawParamMap - key-value pairs map +* paramsSeperator - sepearator, either & or , +* +* @output: rawParams - sorted string of OAuth parameters +* +* @remarks: internal method +* +*--*/ +bool oAuth::getStringFromOAuthKeyValuePairs( const oAuthKeyValuePairs& rawParamMap, + std::string& rawParams, + const std::string& paramsSeperator ) +{ + rawParams = ""; + if( rawParamMap.empty() ) + { + return false; + } + + oAuthKeyValueList keyValueList; + std::string dummyStr; + + /* Push key-value pairs to a list of strings */ + keyValueList.clear(); + oAuthKeyValuePairs::const_iterator itMap = rawParamMap.begin(); + for( ; itMap != rawParamMap.end(); itMap++ ) + { + dummyStr.assign( itMap->first ); + dummyStr.append( "=" ); + if( paramsSeperator == "," ) + { + dummyStr.append( "\"" ); + } + dummyStr.append( itMap->second ); + if( paramsSeperator == "," ) + { + dummyStr.append( "\"" ); + } + keyValueList.push_back( dummyStr ); + } + + /* Sort key-value pairs based on key name */ + keyValueList.sort(); + + /* Now, form a string */ + dummyStr = ""; + oAuthKeyValueList::iterator itKeyValue = keyValueList.begin(); + for( ; itKeyValue != keyValueList.end(); itKeyValue++ ) + { + if( dummyStr.length() ) + { + dummyStr.append( paramsSeperator ); + } + dummyStr.append( itKeyValue->c_str() ); + } + rawParams = dummyStr; + return !rawParams.empty(); +} + +/*++ +* @method: oAuth::extractOAuthTokenKeySecret +* +* @description: this method extracts oauth token key and secret from +* twitter's HTTP response +* +* @input: requestTokenResponse - response from twitter +* +* @output: none +* +*--*/ +bool oAuth::extractOAuthTokenKeySecret( const std::string& requestTokenResponse ) +{ + if( requestTokenResponse.empty() ) + { + return false; + } + + size_t nPos = std::string::npos; + std::string strDummy; + + /* Get oauth_token key */ + nPos = requestTokenResponse.find( oAuthLibDefaults::OAUTHLIB_TOKEN_KEY ); + if( std::string::npos != nPos ) + { + nPos = nPos + oAuthLibDefaults::OAUTHLIB_TOKEN_KEY.length() + strlen( "=" ); + strDummy = requestTokenResponse.substr( nPos ); + nPos = strDummy.find( "&" ); + if( std::string::npos != nPos ) + { + m_oAuthTokenKey = strDummy.substr( 0, nPos ); + } + } + + /* Get oauth_token_secret */ + nPos = requestTokenResponse.find( oAuthLibDefaults::OAUTHLIB_TOKENSECRET_KEY ); + if( std::string::npos != nPos ) + { + nPos = nPos + oAuthLibDefaults::OAUTHLIB_TOKENSECRET_KEY.length() + strlen( "=" ); + strDummy = requestTokenResponse.substr( nPos ); + nPos = strDummy.find( "&" ); + if( std::string::npos != nPos ) + { + m_oAuthTokenSecret = strDummy.substr( 0, nPos ); + } + } + + /* Get screen_name */ + nPos = requestTokenResponse.find( oAuthLibDefaults::OAUTHLIB_SCREENNAME_KEY ); + if( std::string::npos != nPos ) + { + nPos = nPos + oAuthLibDefaults::OAUTHLIB_SCREENNAME_KEY.length() + strlen( "=" ); + strDummy = requestTokenResponse.substr( nPos ); + m_oAuthScreenName = strDummy; + } + + return true; +} + diff --git a/backends/twitter/libtwitcurl/oauthlib.h b/backends/twitter/libtwitcurl/oauthlib.h index b3ec577d9255d47d5d46dcc4c77dac41565f8b4d..5401490b59e1abb9eb15e6797dc2d4a8e214de44 100644 --- a/backends/twitter/libtwitcurl/oauthlib.h +++ b/backends/twitter/libtwitcurl/oauthlib.h @@ -1,93 +1,93 @@ -#ifndef __OAUTHLIB_H__ -#define __OAUTHLIB_H__ - -#include "time.h" -#include -#include -#include -#include -#include -#include -#include - -typedef enum _eOAuthHttpRequestType -{ - eOAuthHttpInvalid = 0, - eOAuthHttpGet, - eOAuthHttpPost, - eOAuthHttpDelete -} eOAuthHttpRequestType; - -typedef std::list oAuthKeyValueList; -typedef std::map oAuthKeyValuePairs; - -class oAuth -{ -public: - oAuth(); - ~oAuth(); - - /* OAuth public methods used by twitCurl */ - void getConsumerKey( std::string& consumerKey /* out */ ); - void setConsumerKey( const std::string& consumerKey /* in */ ); - - void getConsumerSecret( std::string& consumerSecret /* out */ ); - void setConsumerSecret( const std::string& consumerSecret /* in */ ); - - void getOAuthTokenKey( std::string& oAuthTokenKey /* out */ ); - void setOAuthTokenKey( const std::string& oAuthTokenKey /* in */ ); - - void getOAuthTokenSecret( std::string& oAuthTokenSecret /* out */ ); - void setOAuthTokenSecret( const std::string& oAuthTokenSecret /* in */ ); - - void getOAuthScreenName( std::string& oAuthScreenName /* out */ ); - void setOAuthScreenName( const std::string& oAuthScreenName /* in */ ); - - void getOAuthPin( std::string& oAuthPin /* out */ ); - void setOAuthPin( const std::string& oAuthPin /* in */ ); - - bool getOAuthHeader( const eOAuthHttpRequestType eType, /* in */ - const std::string& rawUrl, /* in */ - const std::string& rawData, /* in */ - std::string& oAuthHttpHeader, /* out */ - const bool includeOAuthVerifierPin = false /* in */ ); - - bool extractOAuthTokenKeySecret( const std::string& requestTokenResponse /* in */ ); - - oAuth clone(); - -private: - - /* OAuth data */ - std::string m_consumerKey; - std::string m_consumerSecret; - std::string m_oAuthTokenKey; - std::string m_oAuthTokenSecret; - std::string m_oAuthPin; - std::string m_nonce; - std::string m_timeStamp; - std::string m_oAuthScreenName; - - /* OAuth twitter related utility methods */ - void buildOAuthRawDataKeyValPairs( const std::string& rawData, /* in */ - bool urlencodeData, /* in */ - oAuthKeyValuePairs& rawDataKeyValuePairs /* out */ ); - - bool buildOAuthTokenKeyValuePairs( const bool includeOAuthVerifierPin, /* in */ - const std::string& oauthSignature, /* in */ - oAuthKeyValuePairs& keyValueMap /* out */, - const bool generateTimestamp /* in */ ); - - bool getStringFromOAuthKeyValuePairs( const oAuthKeyValuePairs& rawParamMap, /* in */ - std::string& rawParams, /* out */ - const std::string& paramsSeperator /* in */ ); - - bool getSignature( const eOAuthHttpRequestType eType, /* in */ - const std::string& rawUrl, /* in */ - const oAuthKeyValuePairs& rawKeyValuePairs, /* in */ - std::string& oAuthSignature /* out */ ); - - void generateNonceTimeStamp(); -}; - -#endif // __OAUTHLIB_H__ +#ifndef __OAUTHLIB_H__ +#define __OAUTHLIB_H__ + +#include "time.h" +#include +#include +#include +#include +#include +#include +#include + +typedef enum _eOAuthHttpRequestType +{ + eOAuthHttpInvalid = 0, + eOAuthHttpGet, + eOAuthHttpPost, + eOAuthHttpDelete +} eOAuthHttpRequestType; + +typedef std::list oAuthKeyValueList; +typedef std::map oAuthKeyValuePairs; + +class oAuth +{ +public: + oAuth(); + ~oAuth(); + + /* OAuth public methods used by twitCurl */ + void getConsumerKey( std::string& consumerKey /* out */ ); + void setConsumerKey( const std::string& consumerKey /* in */ ); + + void getConsumerSecret( std::string& consumerSecret /* out */ ); + void setConsumerSecret( const std::string& consumerSecret /* in */ ); + + void getOAuthTokenKey( std::string& oAuthTokenKey /* out */ ); + void setOAuthTokenKey( const std::string& oAuthTokenKey /* in */ ); + + void getOAuthTokenSecret( std::string& oAuthTokenSecret /* out */ ); + void setOAuthTokenSecret( const std::string& oAuthTokenSecret /* in */ ); + + void getOAuthScreenName( std::string& oAuthScreenName /* out */ ); + void setOAuthScreenName( const std::string& oAuthScreenName /* in */ ); + + void getOAuthPin( std::string& oAuthPin /* out */ ); + void setOAuthPin( const std::string& oAuthPin /* in */ ); + + bool getOAuthHeader( const eOAuthHttpRequestType eType, /* in */ + const std::string& rawUrl, /* in */ + const std::string& rawData, /* in */ + std::string& oAuthHttpHeader, /* out */ + const bool includeOAuthVerifierPin = false /* in */ ); + + bool extractOAuthTokenKeySecret( const std::string& requestTokenResponse /* in */ ); + + oAuth clone(); + +private: + + /* OAuth data */ + std::string m_consumerKey; + std::string m_consumerSecret; + std::string m_oAuthTokenKey; + std::string m_oAuthTokenSecret; + std::string m_oAuthPin; + std::string m_nonce; + std::string m_timeStamp; + std::string m_oAuthScreenName; + + /* OAuth twitter related utility methods */ + void buildOAuthRawDataKeyValPairs( const std::string& rawData, /* in */ + bool urlencodeData, /* in */ + oAuthKeyValuePairs& rawDataKeyValuePairs /* out */ ); + + bool buildOAuthTokenKeyValuePairs( const bool includeOAuthVerifierPin, /* in */ + const std::string& oauthSignature, /* in */ + oAuthKeyValuePairs& keyValueMap /* out */, + const bool generateTimestamp /* in */ ); + + bool getStringFromOAuthKeyValuePairs( const oAuthKeyValuePairs& rawParamMap, /* in */ + std::string& rawParams, /* out */ + const std::string& paramsSeperator /* in */ ); + + bool getSignature( const eOAuthHttpRequestType eType, /* in */ + const std::string& rawUrl, /* in */ + const oAuthKeyValuePairs& rawKeyValuePairs, /* in */ + std::string& oAuthSignature /* out */ ); + + void generateNonceTimeStamp(); +}; + +#endif // __OAUTHLIB_H__ diff --git a/backends/twitter/libtwitcurl/twitcurl.cpp b/backends/twitter/libtwitcurl/twitcurl.cpp index bce135c61b54b2bf62c38797ef8307a7c29defe8..23abe312970f7c5c545c5808e6e89fdef8b20b51 100644 --- a/backends/twitter/libtwitcurl/twitcurl.cpp +++ b/backends/twitter/libtwitcurl/twitcurl.cpp @@ -1,2292 +1,2292 @@ -#define NOMINMAX -#include -#include -#include "twitcurlurls.h" -#include "twitcurl.h" -#include "urlencode.h" - -/*++ -* @method: twitCurl::twitCurl -* -* @description: constructor -* -* @input: none -* -* @output: none -* -*--*/ -twitCurl::twitCurl(): -m_curlHandle( NULL ), -m_curlProxyParamsSet( false ), -m_curlLoginParamsSet( false ), -m_curlCallbackParamsSet( false ), -m_eApiFormatType( twitCurlTypes::eTwitCurlApiFormatJson ), -m_eProtocolType( twitCurlTypes::eTwitCurlProtocolHttps ) -{ - /* Alloc memory for cURL error responses */ - m_errorBuffer = (char*)malloc( twitCurlDefaults::TWITCURL_DEFAULT_BUFFSIZE ); - - /* Clear callback buffers */ - clearCurlCallbackBuffers(); - - /* Initialize cURL */ - m_curlHandle = curl_easy_init(); - if( NULL == m_curlHandle ) - { - std::string dummyStr; - getLastCurlError( dummyStr ); - } - curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYPEER, 0); -} - -/*++ -* @method: twitCurl::~twitCurl -* -* @description: destructor -* -* @input: none -* -* @output: none -* -*--*/ -twitCurl::~twitCurl() -{ - /* Cleanup cURL */ - if( m_curlHandle ) - { - curl_easy_cleanup( m_curlHandle ); - m_curlHandle = NULL; - } - if( m_errorBuffer ) - { - free( m_errorBuffer ); - m_errorBuffer = NULL; - } -} - -/*++ -* @method: twitCurl::clone -* -* @description: creates a clone of twitcurl object -* -* @input: none -* -* @output: cloned object -* -*--*/ -twitCurl* twitCurl::clone() -{ - twitCurl *cloneObj = new twitCurl(); - - /* cURL proxy data */ - cloneObj->setProxyServerIp(m_proxyServerIp); - cloneObj->setProxyServerPort(m_proxyServerPort); - cloneObj->setProxyUserName(m_proxyUserName); - cloneObj->setProxyPassword(m_proxyPassword); - - /* Twitter data */ - cloneObj->setTwitterUsername(m_twitterUsername); - cloneObj->setTwitterPassword(m_twitterPassword); - - /* OAuth data */ - cloneObj->m_oAuth = m_oAuth.clone(); - - return cloneObj; -} - -/*++ -* @method: twitCurl::isCurlInit -* -* @description: method to check if cURL is initialized properly -* -* @input: none -* -* @output: true if cURL is intialized, otherwise false -* -*--*/ -bool twitCurl::isCurlInit() -{ - return ( NULL != m_curlHandle ) ? true : false; -} - -/*++ -* @method: twitCurl::getTwitterUsername -* -* @description: method to get stored Twitter username -* -* @input: none -* -* @output: twitter username -* -*--*/ -std::string& twitCurl::getTwitterUsername() -{ - return m_twitterUsername; -} - -/*++ -* @method: twitCurl::getTwitterPassword -* -* @description: method to get stored Twitter password -* -* @input: none -* -* @output: twitter password -* -*--*/ -std::string& twitCurl::getTwitterPassword() -{ - return m_twitterPassword; -} - -/*++ -* @method: twitCurl::setTwitterUsername -* -* @description: method to set username -* -* @input: userName -* -* @output: none -* -*--*/ -void twitCurl::setTwitterUsername( std::string& userName ) -{ - if( userName.length() ) - { - m_twitterUsername = userName; - m_curlLoginParamsSet = false; - } -} - -/*++ -* @method: twitCurl::setTwitterPassword -* -* @description: method to set password -* -* @input: passWord -* -* @output: none -* -*--*/ -void twitCurl::setTwitterPassword( std::string& passWord ) -{ - if( passWord.length() ) - { - m_twitterPassword = passWord; - m_curlLoginParamsSet = false; - } -} - -/*++ -* @method: twitCurl::getProxyServerIp -* -* @description: method to get proxy server IP address -* -* @input: none -* -* @output: proxy server IP address -* -*--*/ -std::string& twitCurl::getProxyServerIp() -{ - return m_proxyServerIp; -} - -/*++ -* @method: twitCurl::getProxyServerPort -* -* @description: method to get proxy server port -* -* @input: none -* -* @output: proxy server port -* -*--*/ -std::string& twitCurl::getProxyServerPort() -{ - return m_proxyServerPort; -} - -/*++ -* @method: twitCurl::getProxyUserName -* -* @description: method to get proxy user name -* -* @input: none -* -* @output: proxy server user name -* -*--*/ -std::string& twitCurl::getProxyUserName() -{ - return m_proxyUserName; -} - -/*++ -* @method: twitCurl::getProxyPassword -* -* @description: method to get proxy server password -* -* @input: none -* -* @output: proxy server password -* -*--*/ -std::string& twitCurl::getProxyPassword() -{ - return m_proxyPassword; -} - -/*++ -* @method: twitCurl::setProxyServerIp -* -* @description: method to set proxy server IP address -* -* @input: proxyServerIp -* -* @output: none -* -*--*/ -void twitCurl::setProxyServerIp( std::string& proxyServerIp ) -{ - if( proxyServerIp.length() ) - { - m_proxyServerIp = proxyServerIp; - /* - * Reset the flag so that next cURL http request - * would set proxy details again into cURL. - */ - m_curlProxyParamsSet = false; - } -} - -/*++ -* @method: twitCurl::setProxyServerPort -* -* @description: method to set proxy server port -* -* @input: proxyServerPort -* -* @output: none -* -*--*/ -void twitCurl::setProxyServerPort( std::string& proxyServerPort ) -{ - if( proxyServerPort.length() ) - { - m_proxyServerPort = proxyServerPort; - /* - * Reset the flag so that next cURL http request - * would set proxy details again into cURL. - */ - m_curlProxyParamsSet = false; - } -} - -/*++ -* @method: twitCurl::setProxyUserName -* -* @description: method to set proxy server username -* -* @input: proxyUserName -* -* @output: none -* -*--*/ -void twitCurl::setProxyUserName( std::string& proxyUserName ) -{ - if( proxyUserName.length() ) - { - m_proxyUserName = proxyUserName; - /* - * Reset the flag so that next cURL http request - * would set proxy details again into cURL. - */ - m_curlProxyParamsSet = false; - } -} - -/*++ -* @method: twitCurl::setProxyPassword -* -* @description: method to set proxy server password -* -* @input: proxyPassword -* -* @output: none -* -*--*/ -void twitCurl::setProxyPassword( std::string& proxyPassword ) -{ - if( proxyPassword.length() ) - { - m_proxyPassword = proxyPassword; - /* - * Reset the flag so that next cURL http request - * would set proxy details again into cURL. - */ - m_curlProxyParamsSet = false; - } -} - -/*++ -* @method: twitCurl::search -* -* @description: method to return tweets that match a specified query. -* -* @input: searchQuery - search query in string format -* resultCount - optional search result count -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -* @note: Only ATOM and JSON format supported. -* -*--*/ -bool twitCurl::search( std::string& searchQuery, std::string resultCount ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_SEARCH_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] + - twitCurlDefaults::TWITCURL_URL_SEP_QUES + twitCurlDefaults::TWITCURL_SEARCHQUERYSTRING + - searchQuery; - - /* Add number of results count if provided */ - if( resultCount.size() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + - twitCurlDefaults::TWITCURL_COUNT + urlencode( resultCount ); - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::statusUpdate -* -* @description: method to update new status message in twitter profile -* -* @input: newStatus - status message text -* inReplyToStatusId - optional status id to we're replying to -* -* @output: true if POST is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::statusUpdate( std::string& newStatus, std::string inReplyToStatusId ) -{ - if( newStatus.empty() ) - { - return false; - } - - /* Prepare new status message */ - std::string newStatusMsg = twitCurlDefaults::TWITCURL_STATUSSTRING + urlencode( newStatus ); - - /* Append status id to which we're replying to */ - if( inReplyToStatusId.size() ) - { - newStatusMsg += twitCurlDefaults::TWITCURL_URL_SEP_AMP + - twitCurlDefaults::TWITCURL_INREPLYTOSTATUSID + - urlencode( inReplyToStatusId ); - } - - /* Perform POST */ - return performPost( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_STATUSUPDATE_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - newStatusMsg ); -} - -/*++ -* @method: twitCurl::statusShowById -* -* @description: method to get a status message by its id -* -* @input: statusId - a number in std::string format -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::statusShowById( std::string& statusId ) -{ - if( statusId.empty() ) - { - return false; - } - - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_STATUSSHOW_URL + statusId + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::statusDestroyById -* -* @description: method to delete a status message by its id -* -* @input: statusId - a number in std::string format -* -* @output: true if DELETE is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::statusDestroyById( std::string& statusId ) -{ - if( statusId.empty() ) - { - return false; - } - - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_STATUDESTROY_URL + statusId + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Perform DELETE */ - return performDelete( buildUrl ); -} - -/*++ -* @method: twitCurl::retweetById -* -* @description: method to RETWEET a status message by its id -* -* @input: statusId - a number in std::string format -* -* @output: true if RETWEET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::retweetById( std::string& statusId ) -{ - if( statusId.empty() ) - { - return false; - } - - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_RETWEET_URL + statusId + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Send some dummy data in POST */ - std::string dummyData = twitCurlDefaults::TWITCURL_TEXTSTRING + - urlencode( std::string( "dummy" ) ); - - /* Perform Retweet */ - return performPost( buildUrl, dummyData ); -} - -/*++ -* @method: twitCurl::timelineHomeGet -* -* @description: method to get home timeline -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::timelineHomeGet( std::string sinceId ) -{ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_HOME_TIMELINE_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - if( sinceId.length() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + twitCurlDefaults::TWITCURL_SINCEID + sinceId; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::timelinePublicGet -* -* @description: method to get public timeline -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::timelinePublicGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_PUBLIC_TIMELINE_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::featuredUsersGet -* -* @description: method to get featured users -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::featuredUsersGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FEATURED_USERS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::timelineFriendsGet -* -* @description: method to get friends timeline -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::timelineFriendsGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FRIENDS_TIMELINE_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::mentionsGet -* -* @description: method to get mentions -* -* @input: sinceId - String specifying since id parameter -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::mentionsGet( std::string sinceId ) -{ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_MENTIONS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - if( sinceId.length() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + twitCurlDefaults::TWITCURL_SINCEID + sinceId; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::timelineUserGet -* -* @description: method to get mentions -* -* @input: trimUser - Trim user name if true -* tweetCount - Number of tweets to get. Max 200. -* userInfo - screen name or user id in string format, -* isUserId - true if userInfo contains an id -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::timelineUserGet( bool trimUser, bool includeRetweets, unsigned int tweetCount, - std::string userInfo, bool isUserId ) -{ - /* Prepare URL */ - std::string buildUrl; - - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_USERTIMELINE_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - if( userInfo.empty() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES; - } - - if( tweetCount ) - { - if( tweetCount > twitCurlDefaults::MAX_TIMELINE_TWEET_COUNT ) - { - tweetCount = twitCurlDefaults::MAX_TIMELINE_TWEET_COUNT; - } - std::stringstream tmpStrm; - tmpStrm << twitCurlDefaults::TWITCURL_URL_SEP_AMP + twitCurlDefaults::TWITCURL_COUNT << tweetCount; - buildUrl += tmpStrm.str(); - tmpStrm.str().clear(); - } - - if( includeRetweets ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + twitCurlDefaults::TWITCURL_INCRETWEETS; - } - - if( trimUser ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + twitCurlDefaults::TWITCURL_TRIMUSER; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::userLookup -* -* @description: method to get a number of user's profiles -* -* @input: userInfo - vector of screen names or user ids -* isUserId - true if userInfo contains an id -* -* @output: true if POST is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::userLookup( std::vector &userInfo, bool isUserId ) -{ - if( userInfo.empty() ) - { - return false; - } - - std::string userIds = ""; - std::string sep = ""; - for( unsigned int i = 0 ; i < std::min((size_t)100, userInfo.size()); i++, sep = "," ) - { - userIds += sep + userInfo[i]; - } - - userIds = ( isUserId ? twitCurlDefaults::TWITCURL_USERID : twitCurlDefaults::TWITCURL_SCREENNAME ) + - urlencode( userIds ); - - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_LOOKUPUSERS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Perform POST */ - return performPost( buildUrl, userIds); -} - -/*++ -* @method: twitCurl::userGet -* -* @description: method to get a user's profile -* -* @input: userInfo - screen name or user id in string format, -* isUserId - true if userInfo contains an id -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::userGet( std::string& userInfo, bool isUserId ) -{ - if( userInfo.empty() ) - { - return false; - } - - /* Set URL */ - std::string buildUrl; - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_SHOWUSERS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::friendsGet -* -* @description: method to get a user's friends -* -* @input: userInfo - screen name or user id in string format, -* isUserId - true if userInfo contains an id -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::friendsGet( std::string userInfo, bool isUserId ) -{ - /* Set URL */ - std::string buildUrl; - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_SHOWFRIENDS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::followersGet -* -* @description: method to get a user's followers -* -* @input: userInfo - screen name or user id in string format, -* isUserId - true if userInfo contains an id -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::followersGet( std::string userInfo, bool isUserId ) -{ - /* Prepare URL */ - std::string buildUrl; - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_SHOWFOLLOWERS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::directMessageGet -* -* @description: method to get direct messages -* -* @input: since id -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::directMessageGet( std::string sinceId ) -{ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_DIRECTMESSAGES_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - if( sinceId.length() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + twitCurlDefaults::TWITCURL_SINCEID + sinceId; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::directMessageSend -* -* @description: method to send direct message to a user -* -* @input: userInfo - screen name or user id of a user to whom message needs to be sent, -* dMsg - message -* isUserId - true if userInfo contains target user's id -* -* @output: true if POST is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::directMessageSend( std::string& userInfo, std::string& dMsg, bool isUserId ) -{ - if( userInfo.empty() || dMsg.empty() ) - { - return false; - } - - /* Prepare new direct message */ - std::string newDm = twitCurlDefaults::TWITCURL_TEXTSTRING + urlencode( dMsg ); - - /* Prepare URL */ - std::string buildUrl; - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_DIRECTMESSAGENEW_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - /* Perform POST */ - return performPost( buildUrl, newDm ); -} - -/*++ -* @method: twitCurl::directMessageGetSent -* -* @description: method to get sent direct messages -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::directMessageGetSent() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_DIRECTMESSAGESSENT_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::directMessageDestroyById -* -* @description: method to delete direct messages by its id -* -* @input: dMsgId - id of direct message in string format -* -* @output: true if DELETE is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::directMessageDestroyById( std::string& dMsgId ) -{ - if( dMsgId.empty() ) - { - return false; - } - - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_DIRECTMESSAGEDESTROY_URL + dMsgId + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Perform DELETE */ - return performDelete( buildUrl ); -} - -/*++ -* @method: twitCurl::friendshipCreate -* -* @description: method to add a twitter user as friend (follow a user) -* -* @input: userInfo - user id or screen name of a user -* isUserId - true if userInfo contains a user id instead of screen name -* -* @output: true if POST is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::friendshipCreate( std::string& userInfo, bool isUserId ) -{ - if( userInfo.empty() ) - { - return false; - } - - /* Prepare URL */ - std::string buildUrl; - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FRIENDSHIPSCREATE_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - /* Send some dummy data in POST */ - std::string dummyData = twitCurlDefaults::TWITCURL_TEXTSTRING + - urlencode( std::string( "dummy" ) ); - - /* Perform POST */ - return performPost( buildUrl, dummyData ); -} - -/*++ -* @method: twitCurl::friendshipDestroy -* -* @description: method to delete a twitter user from friend list (unfollow a user) -* -* @input: userInfo - user id or screen name of a user -* isUserId - true if userInfo contains a user id instead of screen name -* -* @output: true if DELETE is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::friendshipDestroy( std::string& userInfo, bool isUserId ) -{ - if( userInfo.empty() ) - { - return false; - } - - /* Prepare URL */ - std::string buildUrl; - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FRIENDSHIPSDESTROY_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - /* Perform DELETE */ - return performDelete( buildUrl ); -} - -/*++ -* @method: twitCurl::friendshipShow -* -* @description: method to show all friends -* -* @input: userInfo - user id or screen name of a user of whom friends need to be shown -* isUserId - true if userInfo contains a user id instead of screen name -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::friendshipShow( std::string& userInfo, bool isUserId ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FRIENDSHIPSSHOW_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - if( userInfo.length() ) - { - /* Append username to the URL */ - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES; - if( isUserId ) - { - buildUrl += twitCurlDefaults::TWITCURL_TARGETUSERID; - } - else - { - buildUrl += twitCurlDefaults::TWITCURL_TARGETSCREENNAME; - } - buildUrl += userInfo; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::friendsIdsGet -* -* @description: method to show IDs of all friends of a twitter user -* -* @input: userInfo - user id or screen name of a user -* isUserId - true if userInfo contains a user id instead of screen name -* nextCursor - next cursor string returned from a previous call -* to this API, otherwise an empty string -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::friendsIdsGet( std::string& nextCursor, std::string& userInfo, bool isUserId ) -{ - /* Prepare URL */ - std::string buildUrl; - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FRIENDSIDS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - if( buildUrl.length() && nextCursor.length() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + - twitCurlDefaults::TWITCURL_NEXT_CURSOR + - nextCursor; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::followersIdsGet -* -* @description: method to show IDs of all followers of a twitter user -* -* @input: userInfo - user id or screen name of a user -* isUserId - true if userInfo contains a user id instead of screen name -* nextCursor - next cursor string returned from a previous call -* to this API, otherwise an empty string -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::followersIdsGet( std::string& nextCursor, std::string& userInfo, bool isUserId ) -{ - /* Prepare URL */ - std::string buildUrl; - utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FOLLOWERSIDS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], - userInfo, isUserId ); - - if( buildUrl.length() && nextCursor.length() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + - twitCurlDefaults::TWITCURL_NEXT_CURSOR + - nextCursor; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::accountRateLimitGet -* -* @description: method to get API rate limit of current user -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::accountRateLimitGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_ACCOUNTRATELIMIT_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::accountVerifyCredGet -* -* @description: method to get information on user identified by given credentials -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::accountVerifyCredGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_ACCOUNTVERIFYCRED_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::favoriteGet -* -* @description: method to get favorite users' statuses -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::favoriteGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FAVORITESGET_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::favoriteCreate -* -* @description: method to favorite a status message -* -* @input: statusId - id in string format of the status to be favorited -* -* @output: true if POST is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::favoriteCreate( std::string& statusId ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FAVORITECREATE_URL + statusId + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Send some dummy data in POST */ - std::string dummyData = twitCurlDefaults::TWITCURL_TEXTSTRING + - urlencode( std::string( "dummy" ) ); - - /* Perform POST */ - return performPost( buildUrl, dummyData ); -} - -/*++ -* @method: twitCurl::favoriteDestroy -* -* @description: method to delete a favorited the status -* -* @input: statusId - id in string format of the favorite status to be deleted -* -* @output: true if DELETE is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::favoriteDestroy( std::string& statusId ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_FAVORITEDESTROY_URL + statusId + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Perform DELETE */ - return performDelete( buildUrl ); -} - -/*++ -* @method: twitCurl::blockCreate -* -* @description: method to block a user -* -* @input: userInfo - user id or screen name who needs to be blocked -* -* @output: true if POST is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::blockCreate( std::string& userInfo ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_BLOCKSCREATE_URL + userInfo + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Send some dummy data in POST */ - std::string dummyData = twitCurlDefaults::TWITCURL_TEXTSTRING + - urlencode( std::string( "dummy" ) ); - - /* Perform POST */ - return performPost( buildUrl, dummyData ); -} - -/*++ -* @method: twitCurl::blockDestroy -* -* @description: method to unblock a user -* -* @input: userInfo - user id or screen name who need to unblocked -* -* @output: true if DELETE is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::blockDestroy( std::string& userInfo ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_BLOCKSDESTROY_URL + userInfo + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Perform DELETE */ - return performDelete( buildUrl ); -} - -/*++ -* @method: twitCurl::blockListGet -* -* @description: method to get list of users blocked by authenticated user -* -* @input: includeEntities - indicates whether or not to include 'entities' node -* skipStatus - indicates whether or not to include status for returned users -* nextCursor - next cursor string returned from a previous call -* to this API, otherwise an empty string -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::blockListGet( std::string& nextCursor, bool includeEntities, bool skipStatus ) -{ - /* Prepare URL */ - std::string buildUrl, urlParams; - - buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_BLOCKSLIST_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - if( includeEntities ) - { - urlParams += twitCurlDefaults::TWITCURL_INCLUDE_ENTITIES + std::string("true"); - } - if( skipStatus ) - { - if( urlParams.length() ) - { - urlParams += twitCurlDefaults::TWITCURL_URL_SEP_AMP; - } - urlParams += twitCurlDefaults::TWITCURL_SKIP_STATUS + std::string("true"); - } - if( nextCursor.length() ) - { - if( urlParams.length() ) - { - urlParams += twitCurlDefaults::TWITCURL_URL_SEP_AMP; - } - urlParams += twitCurlDefaults::TWITCURL_NEXT_CURSOR + nextCursor; - } - if( urlParams.length() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + urlParams; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::blockIdsGet -* -* @description: method to get list of IDs blocked by authenticated user -* -* @input: stringifyIds - indicates whether or not returned ids should -* be in string format -* nextCursor - next cursor string returned from a previous call -* to this API, otherwise an empty string -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::blockIdsGet( std::string& nextCursor, bool stringifyIds ) -{ - /* Prepare URL */ - std::string buildUrl, urlParams; - - buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_BLOCKSIDS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - if( stringifyIds ) - { - urlParams += twitCurlDefaults::TWITCURL_STRINGIFY_IDS + std::string("true"); - } - if( nextCursor.length() ) - { - if( urlParams.length() ) - { - urlParams += twitCurlDefaults::TWITCURL_URL_SEP_AMP; - } - urlParams += twitCurlDefaults::TWITCURL_NEXT_CURSOR + nextCursor; - } - if( urlParams.length() ) - { - buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + urlParams; - } - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::savedSearchGet -* -* @description: gets authenticated user's saved search queries. -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::savedSearchGet( ) -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_SAVEDSEARCHGET_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::savedSearchShow -* -* @description: method to retrieve the data for a saved search owned by the authenticating user -* specified by the given id. -* -* @input: searchId - id in string format of the search to be displayed -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::savedSearchShow( std::string& searchId ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_SAVEDSEARCHSHOW_URL + searchId + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Perform GET */ - return performGet( buildUrl ); -} - -/*++ -* @method: twitCurl::savedSearchCreate -* -* @description: creates a saved search for the authenticated user -* -* @input: query - the query of the search the user would like to save -* -* @output: true if POST is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::savedSearchCreate( std::string& query ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_SAVEDSEARCHCREATE_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Send some dummy data in POST */ - std::string queryStr = twitCurlDefaults::TWITCURL_QUERYSTRING + urlencode( query ); - - /* Perform POST */ - return performPost( buildUrl, queryStr ); -} - - -/*++ -* @method: twitCurl::savedSearchDestroy -* -* @description: method to destroy a saved search for the authenticated user. The search specified -* by id must be owned by the authenticating user. -* -* @input: searchId - search id of item to be deleted -* -* @output: true if DELETE is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::savedSearchDestroy( std::string& searchId ) -{ - /* Prepare URL */ - std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_SAVEDSEARCHDESTROY_URL + searchId + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; - - /* Perform DELETE */ - return performDelete( buildUrl ); -} - - -/*++ -* @method: twitCurl::trendsGet() -* -* @description: gets trends. -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::trendsGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_TRENDS_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - - -/*++ -* @method: twitCurl::trendsDailyGet() -* -* @description: gets daily trends. -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::trendsDailyGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_TRENDSDAILY_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::trendsWeeklyGet() -* -* @description: gets weekly trends. -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::trendsWeeklyGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_TRENDSWEEKLY_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::trendsCurrentGet() -* -* @description: gets current trends. -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::trendsCurrentGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_TRENDSCURRENT_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::trendsAvailableGet() -* -* @description: gets available trends. -* -* @input: none -* -* @output: true if GET is success, otherwise false. This does not check http -* response by twitter. Use getLastWebResponse() for that. -* -*--*/ -bool twitCurl::trendsAvailableGet() -{ - /* Perform GET */ - return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - twitterDefaults::TWITCURL_TRENDSAVAILABLE_URL + - twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); -} - -/*++ -* @method: twitCurl::getLastWebResponse -* -* @description: method to get http response for the most recent request sent. -* twitcurl users need to call this method and parse the XML -* data returned by twitter to see what has happened. -* -* @input: outWebResp - string in which twitter's response is supplied back to caller -* -* @output: none -* -*--*/ -void twitCurl::getLastWebResponse( std::string& outWebResp ) -{ - outWebResp = ""; - if( m_callbackData.length() ) - { - outWebResp = m_callbackData; - } -} - -/*++ -* @method: twitCurl::getLastCurlError -* -* @description: method to get cURL error response for most recent http request. -* twitcurl users can call this method if any of the APIs return -* false. -* -* @input: none -* -* @output: none -* -*--*/ -void twitCurl::getLastCurlError( std::string& outErrResp ) -{ - m_errorBuffer[twitCurlDefaults::TWITCURL_DEFAULT_BUFFSIZE-1] = twitCurlDefaults::TWITCURL_EOS; - outErrResp.assign( m_errorBuffer ); -} - -/*++ -* @method: twitCurl::curlCallback -* -* @description: static method to get http response back from cURL. -* this is an internal method, users of twitcurl need not -* use this. -* -* @input: as per cURL convention. -* -* @output: size of data stored in our buffer -* -* @remarks: internal method -* -*--*/ -int twitCurl::curlCallback( char* data, size_t size, size_t nmemb, twitCurl* pTwitCurlObj ) -{ - if( pTwitCurlObj && data ) - { - /* Save http response in twitcurl object's buffer */ - return pTwitCurlObj->saveLastWebResponse( data, ( size*nmemb ) ); - } - return 0; -} - -/*++ -* @method: twitCurl::saveLastWebResponse -* -* @description: method to save http responses. this is an internal method -* and twitcurl users need not use this. -* -* @input: data - character buffer from cURL, -* size - size of character buffer -* -* @output: size of data stored in our buffer -* -* @remarks: internal method -* -*--*/ -int twitCurl::saveLastWebResponse( char*& data, size_t size ) -{ - if( data && size ) - { - /* Append data in our internal buffer */ - m_callbackData.append( data, size ); - return (int)size; - } - return 0; -} - -/*++ -* @method: twitCurl::clearCurlCallbackBuffers -* -* @description: method to clear callback buffers used by cURL. this is an -* internal method and twitcurl users need not use this. -* -* @input: none -* -* @output: none -* -* @remarks: internal method -* -*--*/ -void twitCurl::clearCurlCallbackBuffers() -{ - m_callbackData = ""; - memset( m_errorBuffer, 0, twitCurlDefaults::TWITCURL_DEFAULT_BUFFSIZE ); -} - -/*++ -* @method: twitCurl::prepareCurlProxy -* -* @description: method to set proxy details into cURL. this is an internal method. -* twitcurl users should not use this method, instead use setProxyXxx -* methods to set proxy server information. -* -* @input: none -* -* @output: none -* -* @remarks: internal method -* -*--*/ -void twitCurl::prepareCurlProxy() -{ - if( m_curlProxyParamsSet ) - { - return; - } - - /* Reset existing proxy details in cURL */ - curl_easy_setopt( m_curlHandle, CURLOPT_PROXY, NULL ); - curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERPWD, NULL ); - curl_easy_setopt( m_curlHandle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY ); - - /* Set proxy details in cURL */ - std::string proxyIpPort(""); - if( getProxyServerIp().size() ) - { - utilMakeCurlParams( proxyIpPort, getProxyServerIp(), getProxyServerPort() ); - } - curl_easy_setopt( m_curlHandle, CURLOPT_PROXY, proxyIpPort.c_str() ); - - /* Prepare username and password for proxy server */ - if( m_proxyUserName.length() && m_proxyPassword.length() ) - { - std::string proxyUserPass; - utilMakeCurlParams( proxyUserPass, getProxyUserName(), getProxyPassword() ); - curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERPWD, proxyUserPass.c_str() ); - } - - /* Set the flag to true indicating that proxy info is set in cURL */ - m_curlProxyParamsSet = true; -} - -/*++ -* @method: twitCurl::prepareCurlCallback -* -* @description: method to set callback details into cURL. this is an internal method. -* twitcurl users should not use this method. -* -* @input: none -* -* @output: none -* -* @remarks: internal method -* -*--*/ -void twitCurl::prepareCurlCallback() -{ - if( m_curlCallbackParamsSet ) - { - return; - } - - /* Set buffer to get error */ - curl_easy_setopt( m_curlHandle, CURLOPT_ERRORBUFFER, m_errorBuffer ); - - /* Set callback function to get response */ - curl_easy_setopt( m_curlHandle, CURLOPT_WRITEFUNCTION, curlCallback ); - curl_easy_setopt( m_curlHandle, CURLOPT_WRITEDATA, this ); - - /* Set the flag to true indicating that callback info is set in cURL */ - m_curlCallbackParamsSet = true; -} - -/*++ -* @method: twitCurl::prepareCurlUserPass -* -* @description: method to set twitter credentials into cURL. this is an internal method. -* twitcurl users should not use this method, instead use setTwitterXxx -* methods to set twitter username and password. -* -* @input: none -* -* @output: none -* -* @remarks: internal method -* -*--*/ -void twitCurl::prepareCurlUserPass() -{ - if( m_curlLoginParamsSet ) - { - return; - } - - /* Reset existing username and password stored in cURL */ - curl_easy_setopt( m_curlHandle, CURLOPT_USERPWD, "" ); - - if( getTwitterUsername().size() ) - { - /* Prepare username:password */ - std::string userNamePassword; - utilMakeCurlParams( userNamePassword, getTwitterUsername(), getTwitterPassword() ); - - /* Set username and password */ - curl_easy_setopt( m_curlHandle, CURLOPT_USERPWD, userNamePassword.c_str() ); - } - - /* Set the flag to true indicating that twitter credentials are set in cURL */ - m_curlLoginParamsSet = true; -} - -/*++ -* @method: twitCurl::prepareStandardParams -* -* @description: method to set standard params into cURL. this is an internal method. -* twitcurl users should not use this method. -* -* @input: none -* -* @output: none -* -* @remarks: internal method -* -*--*/ -void twitCurl::prepareStandardParams() -{ - /* Restore any custom request we may have */ - curl_easy_setopt( m_curlHandle, CURLOPT_CUSTOMREQUEST, NULL ); - - /* All supported encodings */ - curl_easy_setopt( m_curlHandle, CURLOPT_ENCODING, "" ); - - /* Clear callback and error buffers */ - clearCurlCallbackBuffers(); - - /* Prepare proxy */ - prepareCurlProxy(); - - /* Prepare cURL callback data and error buffer */ - prepareCurlCallback(); - - /* Prepare username and password for twitter */ - prepareCurlUserPass(); -} - -/*++ -* @method: twitCurl::performGet -* -* @description: method to send http GET request. this is an internal method. -* twitcurl users should not use this method. -* -* @input: getUrl - url -* -* @output: none -* -* @remarks: internal method -* -*--*/ -bool twitCurl::performGet( const std::string& getUrl ) -{ - /* Return if cURL is not initialized */ - if( !isCurlInit() ) - { - return false; - } - - std::string dataStrDummy; - std::string oAuthHttpHeader; - struct curl_slist* pOAuthHeaderList = NULL; - - /* Prepare standard params */ - prepareStandardParams(); - - /* Set OAuth header */ - m_oAuth.getOAuthHeader( eOAuthHttpGet, getUrl, dataStrDummy, oAuthHttpHeader ); - if( oAuthHttpHeader.length() ) - { - pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); - if( pOAuthHeaderList ) - { - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); - } - } - - /* Set http request and url */ - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPGET, 1 ); - curl_easy_setopt( m_curlHandle, CURLOPT_URL, getUrl.c_str() ); - - /* Send http request */ - if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) - { - if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return true; - } - if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return false; -} - -/*++ -* @method: twitCurl::performGetInternal -* -* @description: method to send http GET request. this is an internal method. -* twitcurl users should not use this method. -* -* @input: const std::string& getUrl, const std::string& oAuthHttpHeader -* -* @output: none -* -* @remarks: internal method -* -*--*/ -bool twitCurl::performGetInternal( const std::string& getUrl, - const std::string& oAuthHttpHeader ) -{ - /* Return if cURL is not initialized */ - if( !isCurlInit() ) - { - return false; - } - - struct curl_slist* pOAuthHeaderList = NULL; - - /* Prepare standard params */ - prepareStandardParams(); - - /* Set http request and url */ - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPGET, 1 ); - curl_easy_setopt( m_curlHandle, CURLOPT_URL, getUrl.c_str() ); - - /* Set header */ - if( oAuthHttpHeader.length() ) - { - pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); - if( pOAuthHeaderList ) - { - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); - } - } - - /* Send http request */ - if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) - { - if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return true; - } - if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return false; -} - -/*++ -* @method: twitCurl::performDelete -* -* @description: method to send http DELETE request. this is an internal method. -* twitcurl users should not use this method. -* -* @input: deleteUrl - url -* -* @output: none -* -* @remarks: internal method -* -*--*/ -bool twitCurl::performDelete( const std::string& deleteUrl ) -{ - /* Return if cURL is not initialized */ - if( !isCurlInit() ) - { - return false; - } - - std::string dataStrDummy; - std::string oAuthHttpHeader; - struct curl_slist* pOAuthHeaderList = NULL; - - /* Prepare standard params */ - prepareStandardParams(); - - /* Set OAuth header */ - m_oAuth.getOAuthHeader( eOAuthHttpDelete, deleteUrl, dataStrDummy, oAuthHttpHeader ); - if( oAuthHttpHeader.length() ) - { - pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); - if( pOAuthHeaderList ) - { - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); - } - } - - /* Set http request and url */ - curl_easy_setopt( m_curlHandle, CURLOPT_CUSTOMREQUEST, "DELETE" ); - curl_easy_setopt( m_curlHandle, CURLOPT_URL, deleteUrl.c_str() ); - curl_easy_setopt( m_curlHandle, CURLOPT_COPYPOSTFIELDS, dataStrDummy.c_str() ); - - /* Send http request */ - if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) - { - if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return true; - } - if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return false; -} - -/*++ -* @method: twitCurl::performPost -* -* @description: method to send http POST request. this is an internal method. -* twitcurl users should not use this method. -* -* @input: postUrl - url, -* dataStr - url encoded data to be posted -* -* @output: none -* -* @remarks: internal method -* data value in dataStr must already be url encoded. -* ex: dataStr = "key=urlencode(value)" -* -*--*/ -bool twitCurl::performPost( const std::string& postUrl, std::string dataStr ) -{ - /* Return if cURL is not initialized */ - if( !isCurlInit() ) - { - return false; - } - - std::string oAuthHttpHeader; - struct curl_slist* pOAuthHeaderList = NULL; - - /* Prepare standard params */ - prepareStandardParams(); - - /* Set OAuth header */ - m_oAuth.getOAuthHeader( eOAuthHttpPost, postUrl, dataStr, oAuthHttpHeader ); - if( oAuthHttpHeader.length() ) - { - pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); - if( pOAuthHeaderList ) - { - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); - } - } - - /* Set http request, url and data */ - curl_easy_setopt( m_curlHandle, CURLOPT_POST, 1 ); - curl_easy_setopt( m_curlHandle, CURLOPT_URL, postUrl.c_str() ); - if( dataStr.length() ) - { - curl_easy_setopt( m_curlHandle, CURLOPT_COPYPOSTFIELDS, dataStr.c_str() ); - } - - /* Send http request */ - if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) - { - if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return true; - } - if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return false; -} - -/*++ -* @method: utilMakeCurlParams -* -* @description: utility function to build parameter strings in the format -* required by cURL ("param1:param2"). twitcurl users should -* not use this function. -* -* @input: inParam1 - first parameter, -* inParam2 - second parameter -* -* @output: outStr - built parameter -* -* @remarks: internal method -* -*--*/ -void utilMakeCurlParams( std::string& outStr, std::string& inParam1, std::string& inParam2 ) -{ - outStr = inParam1; - outStr += twitCurlDefaults::TWITCURL_COLON + inParam2; -} - -/*++ -* @method: utilMakeUrlForUser -* -* @description: utility function to build url compatible to twitter. twitcurl -* users should not use this function. -* -* @input: baseUrl - base twitter url, -* userInfo - user name, -* isUserId - indicates if userInfo contains a user id or scree name -* -* @output: outUrl - built url -* -* @remarks: internal method -* -*--*/ -void utilMakeUrlForUser( std::string& outUrl, const std::string& baseUrl, std::string& userInfo, bool isUserId ) -{ - /* Copy base URL */ - outUrl = baseUrl; - - if( userInfo.length() ) - { - /* Append username to the URL */ - outUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES; - if( isUserId ) - { - outUrl += twitCurlDefaults::TWITCURL_USERID; - } - else - { - outUrl += twitCurlDefaults::TWITCURL_SCREENNAME; - } - outUrl += userInfo; - } -} - -/*++ -* @method: twitCurl::getOAuth -* -* @description: method to get a reference to oAuth object. -* -* @input: none -* -* @output: reference to oAuth object -* -*--*/ -oAuth& twitCurl::getOAuth() -{ - return m_oAuth; -} - -/*++ -* @method: twitCurl::oAuthRequestToken -* -* @description: method to get a request token key and secret. this token -* will be used to get authorize user and get PIN from twitter -* -* @input: authorizeUrl is an output parameter. this method will set the url -* in this string. user should visit this link and get PIN from that page. -* -* @output: true if everything went sucessfully, otherwise false -* -*--*/ -bool twitCurl::oAuthRequestToken( std::string& authorizeUrl /* out */ ) -{ - /* Return if cURL is not initialized */ - if( !isCurlInit() ) - { - return false; - } - - /* Get OAuth header for request token */ - std::string oAuthHeader; - authorizeUrl = ""; - if( m_oAuth.getOAuthHeader( eOAuthHttpGet, - twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - oAuthTwitterApiUrls::OAUTHLIB_TWITTER_REQUEST_TOKEN_URL, - std::string( "" ), - oAuthHeader ) ) - { - if( performGetInternal( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - oAuthTwitterApiUrls::OAUTHLIB_TWITTER_REQUEST_TOKEN_URL, - oAuthHeader ) ) - { - /* Tell OAuth object to save access token and secret from web response */ - std::string twitterResp; - getLastWebResponse( twitterResp ); - m_oAuth.extractOAuthTokenKeySecret( twitterResp ); - - /* Get access token and secret from OAuth object */ - std::string oAuthTokenKey; - m_oAuth.getOAuthTokenKey( oAuthTokenKey ); - - /* Build authorize url so that user can visit in browser and get PIN */ - authorizeUrl.assign(twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - oAuthTwitterApiUrls::OAUTHLIB_TWITTER_AUTHORIZE_URL ); - authorizeUrl.append( oAuthTokenKey.c_str() ); - - return true; - } - } - return false; -} - -/*++ -* @method: twitCurl::oAuthAccessToken -* -* @description: method to exchange request token with access token -* -* @input: none -* -* @output: true if everything went sucessfully, otherwise false -* -*--*/ -bool twitCurl::oAuthAccessToken() -{ - /* Return if cURL is not initialized */ - if( !isCurlInit() ) - { - return false; - } - /* Get OAuth header for access token */ - std::string oAuthHeader; - if( m_oAuth.getOAuthHeader( eOAuthHttpGet, - twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - oAuthTwitterApiUrls::OAUTHLIB_TWITTER_ACCESS_TOKEN_URL, - std::string( "" ), - oAuthHeader, true ) ) - { - if( performGetInternal( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + - oAuthTwitterApiUrls::OAUTHLIB_TWITTER_ACCESS_TOKEN_URL, - oAuthHeader ) ) - { - /* Tell OAuth object to save access token and secret from web response */ - std::string twitterResp; - getLastWebResponse( twitterResp ); - m_oAuth.extractOAuthTokenKeySecret( twitterResp ); - - return true; - } - } - return false; -} - -/*++ -* ADDED BY ANTIROOT -* -* @method: twitCurl::oAuthHandlePIN -* -* @description: method to handle user's PIN code from the authentiation URLs -* -* @input: none -* -* @output: true if everything went sucessfully, otherwise false -* -*--*/ -bool twitCurl::oAuthHandlePIN( const std::string& authorizeUrl /* in */ ) -{ - /* Return if cURL is not initialized */ - if( !isCurlInit() ) - { - return false; - } - - std::string dataStr; - std::string oAuthHttpHeader; - std::string authenticityTokenVal; - std::string oauthTokenVal; - std::string pinCodeVal; - unsigned long httpStatusCode = 0; - size_t nPosStart, nPosEnd; - struct curl_slist* pOAuthHeaderList = NULL; - - /* Prepare standard params */ - prepareStandardParams(); - - /* Set OAuth header */ - m_oAuth.getOAuthHeader( eOAuthHttpGet, authorizeUrl, dataStr, oAuthHttpHeader ); - if( oAuthHttpHeader.length() ) - { - pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); - if( pOAuthHeaderList ) - { - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); - } - } - - /* Set http request and url */ - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPGET, 1 ); - curl_easy_setopt( m_curlHandle, CURLOPT_URL, authorizeUrl.c_str() ); - - /* Send http request */ - if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) - { - if( pOAuthHeaderList ) - { - curl_easy_getinfo( m_curlHandle, CURLINFO_HTTP_CODE, &httpStatusCode ); - curl_slist_free_all( pOAuthHeaderList ); - - // Now, let's find the authenticity token and oauth token - nPosStart = m_callbackData.find( oAuthLibDefaults::OAUTHLIB_AUTHENTICITY_TOKEN_TWITTER_RESP_KEY ); - if( std::string::npos == nPosStart ) - { - return false; - } - nPosStart += oAuthLibDefaults::OAUTHLIB_AUTHENTICITY_TOKEN_TWITTER_RESP_KEY.length(); - nPosEnd = m_callbackData.substr( nPosStart ).find( oAuthLibDefaults::OAUTHLIB_TOKEN_END_TAG_TWITTER_RESP ); - if( std::string::npos == nPosEnd ) - { - return false; - } - authenticityTokenVal = m_callbackData.substr( nPosStart, nPosEnd ); - - nPosStart = m_callbackData.find( oAuthLibDefaults::OAUTHLIB_TOKEN_TWITTER_RESP_KEY ); - if( std::string::npos == nPosStart ) - { - return false; - } - nPosStart += oAuthLibDefaults::OAUTHLIB_TOKEN_TWITTER_RESP_KEY.length(); - nPosEnd = m_callbackData.substr( nPosStart ).find( oAuthLibDefaults::OAUTHLIB_TOKEN_END_TAG_TWITTER_RESP ); - if( std::string::npos == nPosEnd ) - { - return false; - } - oauthTokenVal = m_callbackData.substr( nPosStart, nPosEnd ); - } - } - else if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - return false; - } - - // Second phase for the authorization - pOAuthHeaderList = NULL; - oAuthHttpHeader.clear(); - - /* Prepare standard params */ - prepareStandardParams(); - - /* - Now, we need to make a data string for POST operation - which includes oauth token, authenticity token, username, password. - */ - dataStr = oAuthLibDefaults::OAUTHLIB_TOKEN_KEY + "=" + oauthTokenVal + "&" + \ - oAuthLibDefaults::OAUTHLIB_AUTHENTICITY_TOKEN_KEY + "=" + authenticityTokenVal + "&" + \ - oAuthLibDefaults::OAUTHLIB_SESSIONUSERNAME_KEY + "=" + getTwitterUsername() + "&" + \ - oAuthLibDefaults::OAUTHLIB_SESSIONPASSWORD_KEY + "=" + getTwitterPassword(); - - /* Set OAuth header */ - m_oAuth.getOAuthHeader( eOAuthHttpPost, authorizeUrl, dataStr, oAuthHttpHeader ); - if( oAuthHttpHeader.length() ) - { - pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); - if( pOAuthHeaderList ) - { - curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); - } - } - - /* Set http request and url */ - curl_easy_setopt( m_curlHandle, CURLOPT_POST, 1 ); - curl_easy_setopt( m_curlHandle, CURLOPT_URL, authorizeUrl.c_str() ); - curl_easy_setopt( m_curlHandle, CURLOPT_COPYPOSTFIELDS, dataStr.c_str() ); - - /* Send http request */ - if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) - { - if( pOAuthHeaderList ) - { - curl_easy_getinfo( m_curlHandle, CURLINFO_HTTP_CODE, &httpStatusCode ); - curl_slist_free_all( pOAuthHeaderList ); - - // Now, let's find the PIN CODE - nPosStart = m_callbackData.find( oAuthLibDefaults::OAUTHLIB_PIN_TWITTER_RESP_KEY ); - if( std::string::npos == nPosStart ) - { - return false; - } - nPosStart += oAuthLibDefaults::OAUTHLIB_PIN_TWITTER_RESP_KEY.length(); - nPosEnd = m_callbackData.substr( nPosStart ).find( oAuthLibDefaults::OAUTHLIB_PIN_END_TAG_TWITTER_RESP ); - if( std::string::npos == nPosEnd ) - { - return false; - } - pinCodeVal = m_callbackData.substr( nPosStart, nPosEnd ); - getOAuth().setOAuthPin( pinCodeVal ); - return true; - } - } - else if( pOAuthHeaderList ) - { - curl_slist_free_all( pOAuthHeaderList ); - } - return false; -} - +#define NOMINMAX +#include +#include +#include "twitcurlurls.h" +#include "twitcurl.h" +#include "urlencode.h" + +/*++ +* @method: twitCurl::twitCurl +* +* @description: constructor +* +* @input: none +* +* @output: none +* +*--*/ +twitCurl::twitCurl(): +m_curlHandle( NULL ), +m_curlProxyParamsSet( false ), +m_curlLoginParamsSet( false ), +m_curlCallbackParamsSet( false ), +m_eApiFormatType( twitCurlTypes::eTwitCurlApiFormatJson ), +m_eProtocolType( twitCurlTypes::eTwitCurlProtocolHttps ) +{ + /* Alloc memory for cURL error responses */ + m_errorBuffer = (char*)malloc( twitCurlDefaults::TWITCURL_DEFAULT_BUFFSIZE ); + + /* Clear callback buffers */ + clearCurlCallbackBuffers(); + + /* Initialize cURL */ + m_curlHandle = curl_easy_init(); + if( NULL == m_curlHandle ) + { + std::string dummyStr; + getLastCurlError( dummyStr ); + } + curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYPEER, 0); +} + +/*++ +* @method: twitCurl::~twitCurl +* +* @description: destructor +* +* @input: none +* +* @output: none +* +*--*/ +twitCurl::~twitCurl() +{ + /* Cleanup cURL */ + if( m_curlHandle ) + { + curl_easy_cleanup( m_curlHandle ); + m_curlHandle = NULL; + } + if( m_errorBuffer ) + { + free( m_errorBuffer ); + m_errorBuffer = NULL; + } +} + +/*++ +* @method: twitCurl::clone +* +* @description: creates a clone of twitcurl object +* +* @input: none +* +* @output: cloned object +* +*--*/ +twitCurl* twitCurl::clone() +{ + twitCurl *cloneObj = new twitCurl(); + + /* cURL proxy data */ + cloneObj->setProxyServerIp(m_proxyServerIp); + cloneObj->setProxyServerPort(m_proxyServerPort); + cloneObj->setProxyUserName(m_proxyUserName); + cloneObj->setProxyPassword(m_proxyPassword); + + /* Twitter data */ + cloneObj->setTwitterUsername(m_twitterUsername); + cloneObj->setTwitterPassword(m_twitterPassword); + + /* OAuth data */ + cloneObj->m_oAuth = m_oAuth.clone(); + + return cloneObj; +} + +/*++ +* @method: twitCurl::isCurlInit +* +* @description: method to check if cURL is initialized properly +* +* @input: none +* +* @output: true if cURL is intialized, otherwise false +* +*--*/ +bool twitCurl::isCurlInit() +{ + return ( NULL != m_curlHandle ) ? true : false; +} + +/*++ +* @method: twitCurl::getTwitterUsername +* +* @description: method to get stored Twitter username +* +* @input: none +* +* @output: twitter username +* +*--*/ +std::string& twitCurl::getTwitterUsername() +{ + return m_twitterUsername; +} + +/*++ +* @method: twitCurl::getTwitterPassword +* +* @description: method to get stored Twitter password +* +* @input: none +* +* @output: twitter password +* +*--*/ +std::string& twitCurl::getTwitterPassword() +{ + return m_twitterPassword; +} + +/*++ +* @method: twitCurl::setTwitterUsername +* +* @description: method to set username +* +* @input: userName +* +* @output: none +* +*--*/ +void twitCurl::setTwitterUsername( std::string& userName ) +{ + if( userName.length() ) + { + m_twitterUsername = userName; + m_curlLoginParamsSet = false; + } +} + +/*++ +* @method: twitCurl::setTwitterPassword +* +* @description: method to set password +* +* @input: passWord +* +* @output: none +* +*--*/ +void twitCurl::setTwitterPassword( std::string& passWord ) +{ + if( passWord.length() ) + { + m_twitterPassword = passWord; + m_curlLoginParamsSet = false; + } +} + +/*++ +* @method: twitCurl::getProxyServerIp +* +* @description: method to get proxy server IP address +* +* @input: none +* +* @output: proxy server IP address +* +*--*/ +std::string& twitCurl::getProxyServerIp() +{ + return m_proxyServerIp; +} + +/*++ +* @method: twitCurl::getProxyServerPort +* +* @description: method to get proxy server port +* +* @input: none +* +* @output: proxy server port +* +*--*/ +std::string& twitCurl::getProxyServerPort() +{ + return m_proxyServerPort; +} + +/*++ +* @method: twitCurl::getProxyUserName +* +* @description: method to get proxy user name +* +* @input: none +* +* @output: proxy server user name +* +*--*/ +std::string& twitCurl::getProxyUserName() +{ + return m_proxyUserName; +} + +/*++ +* @method: twitCurl::getProxyPassword +* +* @description: method to get proxy server password +* +* @input: none +* +* @output: proxy server password +* +*--*/ +std::string& twitCurl::getProxyPassword() +{ + return m_proxyPassword; +} + +/*++ +* @method: twitCurl::setProxyServerIp +* +* @description: method to set proxy server IP address +* +* @input: proxyServerIp +* +* @output: none +* +*--*/ +void twitCurl::setProxyServerIp( std::string& proxyServerIp ) +{ + if( proxyServerIp.length() ) + { + m_proxyServerIp = proxyServerIp; + /* + * Reset the flag so that next cURL http request + * would set proxy details again into cURL. + */ + m_curlProxyParamsSet = false; + } +} + +/*++ +* @method: twitCurl::setProxyServerPort +* +* @description: method to set proxy server port +* +* @input: proxyServerPort +* +* @output: none +* +*--*/ +void twitCurl::setProxyServerPort( std::string& proxyServerPort ) +{ + if( proxyServerPort.length() ) + { + m_proxyServerPort = proxyServerPort; + /* + * Reset the flag so that next cURL http request + * would set proxy details again into cURL. + */ + m_curlProxyParamsSet = false; + } +} + +/*++ +* @method: twitCurl::setProxyUserName +* +* @description: method to set proxy server username +* +* @input: proxyUserName +* +* @output: none +* +*--*/ +void twitCurl::setProxyUserName( std::string& proxyUserName ) +{ + if( proxyUserName.length() ) + { + m_proxyUserName = proxyUserName; + /* + * Reset the flag so that next cURL http request + * would set proxy details again into cURL. + */ + m_curlProxyParamsSet = false; + } +} + +/*++ +* @method: twitCurl::setProxyPassword +* +* @description: method to set proxy server password +* +* @input: proxyPassword +* +* @output: none +* +*--*/ +void twitCurl::setProxyPassword( std::string& proxyPassword ) +{ + if( proxyPassword.length() ) + { + m_proxyPassword = proxyPassword; + /* + * Reset the flag so that next cURL http request + * would set proxy details again into cURL. + */ + m_curlProxyParamsSet = false; + } +} + +/*++ +* @method: twitCurl::search +* +* @description: method to return tweets that match a specified query. +* +* @input: searchQuery - search query in string format +* resultCount - optional search result count +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +* @note: Only ATOM and JSON format supported. +* +*--*/ +bool twitCurl::search( std::string& searchQuery, std::string resultCount ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_SEARCH_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] + + twitCurlDefaults::TWITCURL_URL_SEP_QUES + twitCurlDefaults::TWITCURL_SEARCHQUERYSTRING + + searchQuery; + + /* Add number of results count if provided */ + if( resultCount.size() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + + twitCurlDefaults::TWITCURL_COUNT + urlencode( resultCount ); + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::statusUpdate +* +* @description: method to update new status message in twitter profile +* +* @input: newStatus - status message text +* inReplyToStatusId - optional status id to we're replying to +* +* @output: true if POST is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::statusUpdate( std::string& newStatus, std::string inReplyToStatusId ) +{ + if( newStatus.empty() ) + { + return false; + } + + /* Prepare new status message */ + std::string newStatusMsg = twitCurlDefaults::TWITCURL_STATUSSTRING + urlencode( newStatus ); + + /* Append status id to which we're replying to */ + if( inReplyToStatusId.size() ) + { + newStatusMsg += twitCurlDefaults::TWITCURL_URL_SEP_AMP + + twitCurlDefaults::TWITCURL_INREPLYTOSTATUSID + + urlencode( inReplyToStatusId ); + } + + /* Perform POST */ + return performPost( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_STATUSUPDATE_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + newStatusMsg ); +} + +/*++ +* @method: twitCurl::statusShowById +* +* @description: method to get a status message by its id +* +* @input: statusId - a number in std::string format +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::statusShowById( std::string& statusId ) +{ + if( statusId.empty() ) + { + return false; + } + + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_STATUSSHOW_URL + statusId + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::statusDestroyById +* +* @description: method to delete a status message by its id +* +* @input: statusId - a number in std::string format +* +* @output: true if DELETE is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::statusDestroyById( std::string& statusId ) +{ + if( statusId.empty() ) + { + return false; + } + + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_STATUDESTROY_URL + statusId + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Perform DELETE */ + return performDelete( buildUrl ); +} + +/*++ +* @method: twitCurl::retweetById +* +* @description: method to RETWEET a status message by its id +* +* @input: statusId - a number in std::string format +* +* @output: true if RETWEET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::retweetById( std::string& statusId ) +{ + if( statusId.empty() ) + { + return false; + } + + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_RETWEET_URL + statusId + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Send some dummy data in POST */ + std::string dummyData = twitCurlDefaults::TWITCURL_TEXTSTRING + + urlencode( std::string( "dummy" ) ); + + /* Perform Retweet */ + return performPost( buildUrl, dummyData ); +} + +/*++ +* @method: twitCurl::timelineHomeGet +* +* @description: method to get home timeline +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::timelineHomeGet( std::string sinceId ) +{ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_HOME_TIMELINE_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + if( sinceId.length() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + twitCurlDefaults::TWITCURL_SINCEID + sinceId; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::timelinePublicGet +* +* @description: method to get public timeline +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::timelinePublicGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_PUBLIC_TIMELINE_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::featuredUsersGet +* +* @description: method to get featured users +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::featuredUsersGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FEATURED_USERS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::timelineFriendsGet +* +* @description: method to get friends timeline +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::timelineFriendsGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FRIENDS_TIMELINE_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::mentionsGet +* +* @description: method to get mentions +* +* @input: sinceId - String specifying since id parameter +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::mentionsGet( std::string sinceId ) +{ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_MENTIONS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + if( sinceId.length() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + twitCurlDefaults::TWITCURL_SINCEID + sinceId; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::timelineUserGet +* +* @description: method to get mentions +* +* @input: trimUser - Trim user name if true +* tweetCount - Number of tweets to get. Max 200. +* userInfo - screen name or user id in string format, +* isUserId - true if userInfo contains an id +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::timelineUserGet( bool trimUser, bool includeRetweets, unsigned int tweetCount, + std::string userInfo, bool isUserId ) +{ + /* Prepare URL */ + std::string buildUrl; + + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_USERTIMELINE_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + if( userInfo.empty() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES; + } + + if( tweetCount ) + { + if( tweetCount > twitCurlDefaults::MAX_TIMELINE_TWEET_COUNT ) + { + tweetCount = twitCurlDefaults::MAX_TIMELINE_TWEET_COUNT; + } + std::stringstream tmpStrm; + tmpStrm << twitCurlDefaults::TWITCURL_URL_SEP_AMP + twitCurlDefaults::TWITCURL_COUNT << tweetCount; + buildUrl += tmpStrm.str(); + tmpStrm.str().clear(); + } + + if( includeRetweets ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + twitCurlDefaults::TWITCURL_INCRETWEETS; + } + + if( trimUser ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + twitCurlDefaults::TWITCURL_TRIMUSER; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::userLookup +* +* @description: method to get a number of user's profiles +* +* @input: userInfo - vector of screen names or user ids +* isUserId - true if userInfo contains an id +* +* @output: true if POST is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::userLookup( std::vector &userInfo, bool isUserId ) +{ + if( userInfo.empty() ) + { + return false; + } + + std::string userIds = ""; + std::string sep = ""; + for( unsigned int i = 0 ; i < std::min((size_t)100, userInfo.size()); i++, sep = "," ) + { + userIds += sep + userInfo[i]; + } + + userIds = ( isUserId ? twitCurlDefaults::TWITCURL_USERID : twitCurlDefaults::TWITCURL_SCREENNAME ) + + urlencode( userIds ); + + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_LOOKUPUSERS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Perform POST */ + return performPost( buildUrl, userIds); +} + +/*++ +* @method: twitCurl::userGet +* +* @description: method to get a user's profile +* +* @input: userInfo - screen name or user id in string format, +* isUserId - true if userInfo contains an id +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::userGet( std::string& userInfo, bool isUserId ) +{ + if( userInfo.empty() ) + { + return false; + } + + /* Set URL */ + std::string buildUrl; + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_SHOWUSERS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::friendsGet +* +* @description: method to get a user's friends +* +* @input: userInfo - screen name or user id in string format, +* isUserId - true if userInfo contains an id +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::friendsGet( std::string userInfo, bool isUserId ) +{ + /* Set URL */ + std::string buildUrl; + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_SHOWFRIENDS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::followersGet +* +* @description: method to get a user's followers +* +* @input: userInfo - screen name or user id in string format, +* isUserId - true if userInfo contains an id +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::followersGet( std::string userInfo, bool isUserId ) +{ + /* Prepare URL */ + std::string buildUrl; + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_SHOWFOLLOWERS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::directMessageGet +* +* @description: method to get direct messages +* +* @input: since id +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::directMessageGet( std::string sinceId ) +{ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_DIRECTMESSAGES_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + if( sinceId.length() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + twitCurlDefaults::TWITCURL_SINCEID + sinceId; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::directMessageSend +* +* @description: method to send direct message to a user +* +* @input: userInfo - screen name or user id of a user to whom message needs to be sent, +* dMsg - message +* isUserId - true if userInfo contains target user's id +* +* @output: true if POST is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::directMessageSend( std::string& userInfo, std::string& dMsg, bool isUserId ) +{ + if( userInfo.empty() || dMsg.empty() ) + { + return false; + } + + /* Prepare new direct message */ + std::string newDm = twitCurlDefaults::TWITCURL_TEXTSTRING + urlencode( dMsg ); + + /* Prepare URL */ + std::string buildUrl; + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_DIRECTMESSAGENEW_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + /* Perform POST */ + return performPost( buildUrl, newDm ); +} + +/*++ +* @method: twitCurl::directMessageGetSent +* +* @description: method to get sent direct messages +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::directMessageGetSent() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_DIRECTMESSAGESSENT_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::directMessageDestroyById +* +* @description: method to delete direct messages by its id +* +* @input: dMsgId - id of direct message in string format +* +* @output: true if DELETE is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::directMessageDestroyById( std::string& dMsgId ) +{ + if( dMsgId.empty() ) + { + return false; + } + + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_DIRECTMESSAGEDESTROY_URL + dMsgId + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Perform DELETE */ + return performDelete( buildUrl ); +} + +/*++ +* @method: twitCurl::friendshipCreate +* +* @description: method to add a twitter user as friend (follow a user) +* +* @input: userInfo - user id or screen name of a user +* isUserId - true if userInfo contains a user id instead of screen name +* +* @output: true if POST is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::friendshipCreate( std::string& userInfo, bool isUserId ) +{ + if( userInfo.empty() ) + { + return false; + } + + /* Prepare URL */ + std::string buildUrl; + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FRIENDSHIPSCREATE_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + /* Send some dummy data in POST */ + std::string dummyData = twitCurlDefaults::TWITCURL_TEXTSTRING + + urlencode( std::string( "dummy" ) ); + + /* Perform POST */ + return performPost( buildUrl, dummyData ); +} + +/*++ +* @method: twitCurl::friendshipDestroy +* +* @description: method to delete a twitter user from friend list (unfollow a user) +* +* @input: userInfo - user id or screen name of a user +* isUserId - true if userInfo contains a user id instead of screen name +* +* @output: true if DELETE is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::friendshipDestroy( std::string& userInfo, bool isUserId ) +{ + if( userInfo.empty() ) + { + return false; + } + + /* Prepare URL */ + std::string buildUrl; + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FRIENDSHIPSDESTROY_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + /* Perform DELETE */ + return performDelete( buildUrl ); +} + +/*++ +* @method: twitCurl::friendshipShow +* +* @description: method to show all friends +* +* @input: userInfo - user id or screen name of a user of whom friends need to be shown +* isUserId - true if userInfo contains a user id instead of screen name +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::friendshipShow( std::string& userInfo, bool isUserId ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FRIENDSHIPSSHOW_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + if( userInfo.length() ) + { + /* Append username to the URL */ + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES; + if( isUserId ) + { + buildUrl += twitCurlDefaults::TWITCURL_TARGETUSERID; + } + else + { + buildUrl += twitCurlDefaults::TWITCURL_TARGETSCREENNAME; + } + buildUrl += userInfo; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::friendsIdsGet +* +* @description: method to show IDs of all friends of a twitter user +* +* @input: userInfo - user id or screen name of a user +* isUserId - true if userInfo contains a user id instead of screen name +* nextCursor - next cursor string returned from a previous call +* to this API, otherwise an empty string +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::friendsIdsGet( std::string& nextCursor, std::string& userInfo, bool isUserId ) +{ + /* Prepare URL */ + std::string buildUrl; + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FRIENDSIDS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + if( buildUrl.length() && nextCursor.length() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + + twitCurlDefaults::TWITCURL_NEXT_CURSOR + + nextCursor; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::followersIdsGet +* +* @description: method to show IDs of all followers of a twitter user +* +* @input: userInfo - user id or screen name of a user +* isUserId - true if userInfo contains a user id instead of screen name +* nextCursor - next cursor string returned from a previous call +* to this API, otherwise an empty string +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::followersIdsGet( std::string& nextCursor, std::string& userInfo, bool isUserId ) +{ + /* Prepare URL */ + std::string buildUrl; + utilMakeUrlForUser( buildUrl, twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FOLLOWERSIDS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType], + userInfo, isUserId ); + + if( buildUrl.length() && nextCursor.length() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_AMP + + twitCurlDefaults::TWITCURL_NEXT_CURSOR + + nextCursor; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::accountRateLimitGet +* +* @description: method to get API rate limit of current user +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::accountRateLimitGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_ACCOUNTRATELIMIT_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::accountVerifyCredGet +* +* @description: method to get information on user identified by given credentials +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::accountVerifyCredGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_ACCOUNTVERIFYCRED_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::favoriteGet +* +* @description: method to get favorite users' statuses +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::favoriteGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FAVORITESGET_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::favoriteCreate +* +* @description: method to favorite a status message +* +* @input: statusId - id in string format of the status to be favorited +* +* @output: true if POST is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::favoriteCreate( std::string& statusId ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FAVORITECREATE_URL + statusId + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Send some dummy data in POST */ + std::string dummyData = twitCurlDefaults::TWITCURL_TEXTSTRING + + urlencode( std::string( "dummy" ) ); + + /* Perform POST */ + return performPost( buildUrl, dummyData ); +} + +/*++ +* @method: twitCurl::favoriteDestroy +* +* @description: method to delete a favorited the status +* +* @input: statusId - id in string format of the favorite status to be deleted +* +* @output: true if DELETE is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::favoriteDestroy( std::string& statusId ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_FAVORITEDESTROY_URL + statusId + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Perform DELETE */ + return performDelete( buildUrl ); +} + +/*++ +* @method: twitCurl::blockCreate +* +* @description: method to block a user +* +* @input: userInfo - user id or screen name who needs to be blocked +* +* @output: true if POST is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::blockCreate( std::string& userInfo ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_BLOCKSCREATE_URL + userInfo + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Send some dummy data in POST */ + std::string dummyData = twitCurlDefaults::TWITCURL_TEXTSTRING + + urlencode( std::string( "dummy" ) ); + + /* Perform POST */ + return performPost( buildUrl, dummyData ); +} + +/*++ +* @method: twitCurl::blockDestroy +* +* @description: method to unblock a user +* +* @input: userInfo - user id or screen name who need to unblocked +* +* @output: true if DELETE is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::blockDestroy( std::string& userInfo ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_BLOCKSDESTROY_URL + userInfo + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Perform DELETE */ + return performDelete( buildUrl ); +} + +/*++ +* @method: twitCurl::blockListGet +* +* @description: method to get list of users blocked by authenticated user +* +* @input: includeEntities - indicates whether or not to include 'entities' node +* skipStatus - indicates whether or not to include status for returned users +* nextCursor - next cursor string returned from a previous call +* to this API, otherwise an empty string +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::blockListGet( std::string& nextCursor, bool includeEntities, bool skipStatus ) +{ + /* Prepare URL */ + std::string buildUrl, urlParams; + + buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_BLOCKSLIST_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + if( includeEntities ) + { + urlParams += twitCurlDefaults::TWITCURL_INCLUDE_ENTITIES + std::string("true"); + } + if( skipStatus ) + { + if( urlParams.length() ) + { + urlParams += twitCurlDefaults::TWITCURL_URL_SEP_AMP; + } + urlParams += twitCurlDefaults::TWITCURL_SKIP_STATUS + std::string("true"); + } + if( nextCursor.length() ) + { + if( urlParams.length() ) + { + urlParams += twitCurlDefaults::TWITCURL_URL_SEP_AMP; + } + urlParams += twitCurlDefaults::TWITCURL_NEXT_CURSOR + nextCursor; + } + if( urlParams.length() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + urlParams; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::blockIdsGet +* +* @description: method to get list of IDs blocked by authenticated user +* +* @input: stringifyIds - indicates whether or not returned ids should +* be in string format +* nextCursor - next cursor string returned from a previous call +* to this API, otherwise an empty string +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::blockIdsGet( std::string& nextCursor, bool stringifyIds ) +{ + /* Prepare URL */ + std::string buildUrl, urlParams; + + buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_BLOCKSIDS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + if( stringifyIds ) + { + urlParams += twitCurlDefaults::TWITCURL_STRINGIFY_IDS + std::string("true"); + } + if( nextCursor.length() ) + { + if( urlParams.length() ) + { + urlParams += twitCurlDefaults::TWITCURL_URL_SEP_AMP; + } + urlParams += twitCurlDefaults::TWITCURL_NEXT_CURSOR + nextCursor; + } + if( urlParams.length() ) + { + buildUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES + urlParams; + } + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::savedSearchGet +* +* @description: gets authenticated user's saved search queries. +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::savedSearchGet( ) +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_SAVEDSEARCHGET_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::savedSearchShow +* +* @description: method to retrieve the data for a saved search owned by the authenticating user +* specified by the given id. +* +* @input: searchId - id in string format of the search to be displayed +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::savedSearchShow( std::string& searchId ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_SAVEDSEARCHSHOW_URL + searchId + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Perform GET */ + return performGet( buildUrl ); +} + +/*++ +* @method: twitCurl::savedSearchCreate +* +* @description: creates a saved search for the authenticated user +* +* @input: query - the query of the search the user would like to save +* +* @output: true if POST is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::savedSearchCreate( std::string& query ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_SAVEDSEARCHCREATE_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Send some dummy data in POST */ + std::string queryStr = twitCurlDefaults::TWITCURL_QUERYSTRING + urlencode( query ); + + /* Perform POST */ + return performPost( buildUrl, queryStr ); +} + + +/*++ +* @method: twitCurl::savedSearchDestroy +* +* @description: method to destroy a saved search for the authenticated user. The search specified +* by id must be owned by the authenticating user. +* +* @input: searchId - search id of item to be deleted +* +* @output: true if DELETE is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::savedSearchDestroy( std::string& searchId ) +{ + /* Prepare URL */ + std::string buildUrl = twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_SAVEDSEARCHDESTROY_URL + searchId + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType]; + + /* Perform DELETE */ + return performDelete( buildUrl ); +} + + +/*++ +* @method: twitCurl::trendsGet() +* +* @description: gets trends. +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::trendsGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_TRENDS_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + + +/*++ +* @method: twitCurl::trendsDailyGet() +* +* @description: gets daily trends. +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::trendsDailyGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_TRENDSDAILY_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::trendsWeeklyGet() +* +* @description: gets weekly trends. +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::trendsWeeklyGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_TRENDSWEEKLY_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::trendsCurrentGet() +* +* @description: gets current trends. +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::trendsCurrentGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_TRENDSCURRENT_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::trendsAvailableGet() +* +* @description: gets available trends. +* +* @input: none +* +* @output: true if GET is success, otherwise false. This does not check http +* response by twitter. Use getLastWebResponse() for that. +* +*--*/ +bool twitCurl::trendsAvailableGet() +{ + /* Perform GET */ + return performGet( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + twitterDefaults::TWITCURL_TRENDSAVAILABLE_URL + + twitCurlDefaults::TWITCURL_EXTENSIONFORMATS[m_eApiFormatType] ); +} + +/*++ +* @method: twitCurl::getLastWebResponse +* +* @description: method to get http response for the most recent request sent. +* twitcurl users need to call this method and parse the XML +* data returned by twitter to see what has happened. +* +* @input: outWebResp - string in which twitter's response is supplied back to caller +* +* @output: none +* +*--*/ +void twitCurl::getLastWebResponse( std::string& outWebResp ) +{ + outWebResp = ""; + if( m_callbackData.length() ) + { + outWebResp = m_callbackData; + } +} + +/*++ +* @method: twitCurl::getLastCurlError +* +* @description: method to get cURL error response for most recent http request. +* twitcurl users can call this method if any of the APIs return +* false. +* +* @input: none +* +* @output: none +* +*--*/ +void twitCurl::getLastCurlError( std::string& outErrResp ) +{ + m_errorBuffer[twitCurlDefaults::TWITCURL_DEFAULT_BUFFSIZE-1] = twitCurlDefaults::TWITCURL_EOS; + outErrResp.assign( m_errorBuffer ); +} + +/*++ +* @method: twitCurl::curlCallback +* +* @description: static method to get http response back from cURL. +* this is an internal method, users of twitcurl need not +* use this. +* +* @input: as per cURL convention. +* +* @output: size of data stored in our buffer +* +* @remarks: internal method +* +*--*/ +int twitCurl::curlCallback( char* data, size_t size, size_t nmemb, twitCurl* pTwitCurlObj ) +{ + if( pTwitCurlObj && data ) + { + /* Save http response in twitcurl object's buffer */ + return pTwitCurlObj->saveLastWebResponse( data, ( size*nmemb ) ); + } + return 0; +} + +/*++ +* @method: twitCurl::saveLastWebResponse +* +* @description: method to save http responses. this is an internal method +* and twitcurl users need not use this. +* +* @input: data - character buffer from cURL, +* size - size of character buffer +* +* @output: size of data stored in our buffer +* +* @remarks: internal method +* +*--*/ +int twitCurl::saveLastWebResponse( char*& data, size_t size ) +{ + if( data && size ) + { + /* Append data in our internal buffer */ + m_callbackData.append( data, size ); + return (int)size; + } + return 0; +} + +/*++ +* @method: twitCurl::clearCurlCallbackBuffers +* +* @description: method to clear callback buffers used by cURL. this is an +* internal method and twitcurl users need not use this. +* +* @input: none +* +* @output: none +* +* @remarks: internal method +* +*--*/ +void twitCurl::clearCurlCallbackBuffers() +{ + m_callbackData = ""; + memset( m_errorBuffer, 0, twitCurlDefaults::TWITCURL_DEFAULT_BUFFSIZE ); +} + +/*++ +* @method: twitCurl::prepareCurlProxy +* +* @description: method to set proxy details into cURL. this is an internal method. +* twitcurl users should not use this method, instead use setProxyXxx +* methods to set proxy server information. +* +* @input: none +* +* @output: none +* +* @remarks: internal method +* +*--*/ +void twitCurl::prepareCurlProxy() +{ + if( m_curlProxyParamsSet ) + { + return; + } + + /* Reset existing proxy details in cURL */ + curl_easy_setopt( m_curlHandle, CURLOPT_PROXY, NULL ); + curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERPWD, NULL ); + curl_easy_setopt( m_curlHandle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY ); + + /* Set proxy details in cURL */ + std::string proxyIpPort(""); + if( getProxyServerIp().size() ) + { + utilMakeCurlParams( proxyIpPort, getProxyServerIp(), getProxyServerPort() ); + } + curl_easy_setopt( m_curlHandle, CURLOPT_PROXY, proxyIpPort.c_str() ); + + /* Prepare username and password for proxy server */ + if( m_proxyUserName.length() && m_proxyPassword.length() ) + { + std::string proxyUserPass; + utilMakeCurlParams( proxyUserPass, getProxyUserName(), getProxyPassword() ); + curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERPWD, proxyUserPass.c_str() ); + } + + /* Set the flag to true indicating that proxy info is set in cURL */ + m_curlProxyParamsSet = true; +} + +/*++ +* @method: twitCurl::prepareCurlCallback +* +* @description: method to set callback details into cURL. this is an internal method. +* twitcurl users should not use this method. +* +* @input: none +* +* @output: none +* +* @remarks: internal method +* +*--*/ +void twitCurl::prepareCurlCallback() +{ + if( m_curlCallbackParamsSet ) + { + return; + } + + /* Set buffer to get error */ + curl_easy_setopt( m_curlHandle, CURLOPT_ERRORBUFFER, m_errorBuffer ); + + /* Set callback function to get response */ + curl_easy_setopt( m_curlHandle, CURLOPT_WRITEFUNCTION, curlCallback ); + curl_easy_setopt( m_curlHandle, CURLOPT_WRITEDATA, this ); + + /* Set the flag to true indicating that callback info is set in cURL */ + m_curlCallbackParamsSet = true; +} + +/*++ +* @method: twitCurl::prepareCurlUserPass +* +* @description: method to set twitter credentials into cURL. this is an internal method. +* twitcurl users should not use this method, instead use setTwitterXxx +* methods to set twitter username and password. +* +* @input: none +* +* @output: none +* +* @remarks: internal method +* +*--*/ +void twitCurl::prepareCurlUserPass() +{ + if( m_curlLoginParamsSet ) + { + return; + } + + /* Reset existing username and password stored in cURL */ + curl_easy_setopt( m_curlHandle, CURLOPT_USERPWD, "" ); + + if( getTwitterUsername().size() ) + { + /* Prepare username:password */ + std::string userNamePassword; + utilMakeCurlParams( userNamePassword, getTwitterUsername(), getTwitterPassword() ); + + /* Set username and password */ + curl_easy_setopt( m_curlHandle, CURLOPT_USERPWD, userNamePassword.c_str() ); + } + + /* Set the flag to true indicating that twitter credentials are set in cURL */ + m_curlLoginParamsSet = true; +} + +/*++ +* @method: twitCurl::prepareStandardParams +* +* @description: method to set standard params into cURL. this is an internal method. +* twitcurl users should not use this method. +* +* @input: none +* +* @output: none +* +* @remarks: internal method +* +*--*/ +void twitCurl::prepareStandardParams() +{ + /* Restore any custom request we may have */ + curl_easy_setopt( m_curlHandle, CURLOPT_CUSTOMREQUEST, NULL ); + + /* All supported encodings */ + curl_easy_setopt( m_curlHandle, CURLOPT_ENCODING, "" ); + + /* Clear callback and error buffers */ + clearCurlCallbackBuffers(); + + /* Prepare proxy */ + prepareCurlProxy(); + + /* Prepare cURL callback data and error buffer */ + prepareCurlCallback(); + + /* Prepare username and password for twitter */ + prepareCurlUserPass(); +} + +/*++ +* @method: twitCurl::performGet +* +* @description: method to send http GET request. this is an internal method. +* twitcurl users should not use this method. +* +* @input: getUrl - url +* +* @output: none +* +* @remarks: internal method +* +*--*/ +bool twitCurl::performGet( const std::string& getUrl ) +{ + /* Return if cURL is not initialized */ + if( !isCurlInit() ) + { + return false; + } + + std::string dataStrDummy; + std::string oAuthHttpHeader; + struct curl_slist* pOAuthHeaderList = NULL; + + /* Prepare standard params */ + prepareStandardParams(); + + /* Set OAuth header */ + m_oAuth.getOAuthHeader( eOAuthHttpGet, getUrl, dataStrDummy, oAuthHttpHeader ); + if( oAuthHttpHeader.length() ) + { + pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); + if( pOAuthHeaderList ) + { + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); + } + } + + /* Set http request and url */ + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPGET, 1 ); + curl_easy_setopt( m_curlHandle, CURLOPT_URL, getUrl.c_str() ); + + /* Send http request */ + if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) + { + if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return true; + } + if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return false; +} + +/*++ +* @method: twitCurl::performGetInternal +* +* @description: method to send http GET request. this is an internal method. +* twitcurl users should not use this method. +* +* @input: const std::string& getUrl, const std::string& oAuthHttpHeader +* +* @output: none +* +* @remarks: internal method +* +*--*/ +bool twitCurl::performGetInternal( const std::string& getUrl, + const std::string& oAuthHttpHeader ) +{ + /* Return if cURL is not initialized */ + if( !isCurlInit() ) + { + return false; + } + + struct curl_slist* pOAuthHeaderList = NULL; + + /* Prepare standard params */ + prepareStandardParams(); + + /* Set http request and url */ + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPGET, 1 ); + curl_easy_setopt( m_curlHandle, CURLOPT_URL, getUrl.c_str() ); + + /* Set header */ + if( oAuthHttpHeader.length() ) + { + pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); + if( pOAuthHeaderList ) + { + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); + } + } + + /* Send http request */ + if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) + { + if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return true; + } + if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return false; +} + +/*++ +* @method: twitCurl::performDelete +* +* @description: method to send http DELETE request. this is an internal method. +* twitcurl users should not use this method. +* +* @input: deleteUrl - url +* +* @output: none +* +* @remarks: internal method +* +*--*/ +bool twitCurl::performDelete( const std::string& deleteUrl ) +{ + /* Return if cURL is not initialized */ + if( !isCurlInit() ) + { + return false; + } + + std::string dataStrDummy; + std::string oAuthHttpHeader; + struct curl_slist* pOAuthHeaderList = NULL; + + /* Prepare standard params */ + prepareStandardParams(); + + /* Set OAuth header */ + m_oAuth.getOAuthHeader( eOAuthHttpDelete, deleteUrl, dataStrDummy, oAuthHttpHeader ); + if( oAuthHttpHeader.length() ) + { + pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); + if( pOAuthHeaderList ) + { + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); + } + } + + /* Set http request and url */ + curl_easy_setopt( m_curlHandle, CURLOPT_CUSTOMREQUEST, "DELETE" ); + curl_easy_setopt( m_curlHandle, CURLOPT_URL, deleteUrl.c_str() ); + curl_easy_setopt( m_curlHandle, CURLOPT_COPYPOSTFIELDS, dataStrDummy.c_str() ); + + /* Send http request */ + if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) + { + if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return true; + } + if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return false; +} + +/*++ +* @method: twitCurl::performPost +* +* @description: method to send http POST request. this is an internal method. +* twitcurl users should not use this method. +* +* @input: postUrl - url, +* dataStr - url encoded data to be posted +* +* @output: none +* +* @remarks: internal method +* data value in dataStr must already be url encoded. +* ex: dataStr = "key=urlencode(value)" +* +*--*/ +bool twitCurl::performPost( const std::string& postUrl, std::string dataStr ) +{ + /* Return if cURL is not initialized */ + if( !isCurlInit() ) + { + return false; + } + + std::string oAuthHttpHeader; + struct curl_slist* pOAuthHeaderList = NULL; + + /* Prepare standard params */ + prepareStandardParams(); + + /* Set OAuth header */ + m_oAuth.getOAuthHeader( eOAuthHttpPost, postUrl, dataStr, oAuthHttpHeader ); + if( oAuthHttpHeader.length() ) + { + pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); + if( pOAuthHeaderList ) + { + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); + } + } + + /* Set http request, url and data */ + curl_easy_setopt( m_curlHandle, CURLOPT_POST, 1 ); + curl_easy_setopt( m_curlHandle, CURLOPT_URL, postUrl.c_str() ); + if( dataStr.length() ) + { + curl_easy_setopt( m_curlHandle, CURLOPT_COPYPOSTFIELDS, dataStr.c_str() ); + } + + /* Send http request */ + if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) + { + if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return true; + } + if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return false; +} + +/*++ +* @method: utilMakeCurlParams +* +* @description: utility function to build parameter strings in the format +* required by cURL ("param1:param2"). twitcurl users should +* not use this function. +* +* @input: inParam1 - first parameter, +* inParam2 - second parameter +* +* @output: outStr - built parameter +* +* @remarks: internal method +* +*--*/ +void utilMakeCurlParams( std::string& outStr, std::string& inParam1, std::string& inParam2 ) +{ + outStr = inParam1; + outStr += twitCurlDefaults::TWITCURL_COLON + inParam2; +} + +/*++ +* @method: utilMakeUrlForUser +* +* @description: utility function to build url compatible to twitter. twitcurl +* users should not use this function. +* +* @input: baseUrl - base twitter url, +* userInfo - user name, +* isUserId - indicates if userInfo contains a user id or scree name +* +* @output: outUrl - built url +* +* @remarks: internal method +* +*--*/ +void utilMakeUrlForUser( std::string& outUrl, const std::string& baseUrl, std::string& userInfo, bool isUserId ) +{ + /* Copy base URL */ + outUrl = baseUrl; + + if( userInfo.length() ) + { + /* Append username to the URL */ + outUrl += twitCurlDefaults::TWITCURL_URL_SEP_QUES; + if( isUserId ) + { + outUrl += twitCurlDefaults::TWITCURL_USERID; + } + else + { + outUrl += twitCurlDefaults::TWITCURL_SCREENNAME; + } + outUrl += userInfo; + } +} + +/*++ +* @method: twitCurl::getOAuth +* +* @description: method to get a reference to oAuth object. +* +* @input: none +* +* @output: reference to oAuth object +* +*--*/ +oAuth& twitCurl::getOAuth() +{ + return m_oAuth; +} + +/*++ +* @method: twitCurl::oAuthRequestToken +* +* @description: method to get a request token key and secret. this token +* will be used to get authorize user and get PIN from twitter +* +* @input: authorizeUrl is an output parameter. this method will set the url +* in this string. user should visit this link and get PIN from that page. +* +* @output: true if everything went sucessfully, otherwise false +* +*--*/ +bool twitCurl::oAuthRequestToken( std::string& authorizeUrl /* out */ ) +{ + /* Return if cURL is not initialized */ + if( !isCurlInit() ) + { + return false; + } + + /* Get OAuth header for request token */ + std::string oAuthHeader; + authorizeUrl = ""; + if( m_oAuth.getOAuthHeader( eOAuthHttpGet, + twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + oAuthTwitterApiUrls::OAUTHLIB_TWITTER_REQUEST_TOKEN_URL, + std::string( "" ), + oAuthHeader ) ) + { + if( performGetInternal( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + oAuthTwitterApiUrls::OAUTHLIB_TWITTER_REQUEST_TOKEN_URL, + oAuthHeader ) ) + { + /* Tell OAuth object to save access token and secret from web response */ + std::string twitterResp; + getLastWebResponse( twitterResp ); + m_oAuth.extractOAuthTokenKeySecret( twitterResp ); + + /* Get access token and secret from OAuth object */ + std::string oAuthTokenKey; + m_oAuth.getOAuthTokenKey( oAuthTokenKey ); + + /* Build authorize url so that user can visit in browser and get PIN */ + authorizeUrl.assign(twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + oAuthTwitterApiUrls::OAUTHLIB_TWITTER_AUTHORIZE_URL ); + authorizeUrl.append( oAuthTokenKey.c_str() ); + + return true; + } + } + return false; +} + +/*++ +* @method: twitCurl::oAuthAccessToken +* +* @description: method to exchange request token with access token +* +* @input: none +* +* @output: true if everything went sucessfully, otherwise false +* +*--*/ +bool twitCurl::oAuthAccessToken() +{ + /* Return if cURL is not initialized */ + if( !isCurlInit() ) + { + return false; + } + /* Get OAuth header for access token */ + std::string oAuthHeader; + if( m_oAuth.getOAuthHeader( eOAuthHttpGet, + twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + oAuthTwitterApiUrls::OAUTHLIB_TWITTER_ACCESS_TOKEN_URL, + std::string( "" ), + oAuthHeader, true ) ) + { + if( performGetInternal( twitCurlDefaults::TWITCURL_PROTOCOLS[m_eProtocolType] + + oAuthTwitterApiUrls::OAUTHLIB_TWITTER_ACCESS_TOKEN_URL, + oAuthHeader ) ) + { + /* Tell OAuth object to save access token and secret from web response */ + std::string twitterResp; + getLastWebResponse( twitterResp ); + m_oAuth.extractOAuthTokenKeySecret( twitterResp ); + + return true; + } + } + return false; +} + +/*++ +* ADDED BY ANTIROOT +* +* @method: twitCurl::oAuthHandlePIN +* +* @description: method to handle user's PIN code from the authentiation URLs +* +* @input: none +* +* @output: true if everything went sucessfully, otherwise false +* +*--*/ +bool twitCurl::oAuthHandlePIN( const std::string& authorizeUrl /* in */ ) +{ + /* Return if cURL is not initialized */ + if( !isCurlInit() ) + { + return false; + } + + std::string dataStr; + std::string oAuthHttpHeader; + std::string authenticityTokenVal; + std::string oauthTokenVal; + std::string pinCodeVal; + unsigned long httpStatusCode = 0; + size_t nPosStart, nPosEnd; + struct curl_slist* pOAuthHeaderList = NULL; + + /* Prepare standard params */ + prepareStandardParams(); + + /* Set OAuth header */ + m_oAuth.getOAuthHeader( eOAuthHttpGet, authorizeUrl, dataStr, oAuthHttpHeader ); + if( oAuthHttpHeader.length() ) + { + pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); + if( pOAuthHeaderList ) + { + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); + } + } + + /* Set http request and url */ + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPGET, 1 ); + curl_easy_setopt( m_curlHandle, CURLOPT_URL, authorizeUrl.c_str() ); + + /* Send http request */ + if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) + { + if( pOAuthHeaderList ) + { + curl_easy_getinfo( m_curlHandle, CURLINFO_HTTP_CODE, &httpStatusCode ); + curl_slist_free_all( pOAuthHeaderList ); + + // Now, let's find the authenticity token and oauth token + nPosStart = m_callbackData.find( oAuthLibDefaults::OAUTHLIB_AUTHENTICITY_TOKEN_TWITTER_RESP_KEY ); + if( std::string::npos == nPosStart ) + { + return false; + } + nPosStart += oAuthLibDefaults::OAUTHLIB_AUTHENTICITY_TOKEN_TWITTER_RESP_KEY.length(); + nPosEnd = m_callbackData.substr( nPosStart ).find( oAuthLibDefaults::OAUTHLIB_TOKEN_END_TAG_TWITTER_RESP ); + if( std::string::npos == nPosEnd ) + { + return false; + } + authenticityTokenVal = m_callbackData.substr( nPosStart, nPosEnd ); + + nPosStart = m_callbackData.find( oAuthLibDefaults::OAUTHLIB_TOKEN_TWITTER_RESP_KEY ); + if( std::string::npos == nPosStart ) + { + return false; + } + nPosStart += oAuthLibDefaults::OAUTHLIB_TOKEN_TWITTER_RESP_KEY.length(); + nPosEnd = m_callbackData.substr( nPosStart ).find( oAuthLibDefaults::OAUTHLIB_TOKEN_END_TAG_TWITTER_RESP ); + if( std::string::npos == nPosEnd ) + { + return false; + } + oauthTokenVal = m_callbackData.substr( nPosStart, nPosEnd ); + } + } + else if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + return false; + } + + // Second phase for the authorization + pOAuthHeaderList = NULL; + oAuthHttpHeader.clear(); + + /* Prepare standard params */ + prepareStandardParams(); + + /* + Now, we need to make a data string for POST operation + which includes oauth token, authenticity token, username, password. + */ + dataStr = oAuthLibDefaults::OAUTHLIB_TOKEN_KEY + "=" + oauthTokenVal + "&" + \ + oAuthLibDefaults::OAUTHLIB_AUTHENTICITY_TOKEN_KEY + "=" + authenticityTokenVal + "&" + \ + oAuthLibDefaults::OAUTHLIB_SESSIONUSERNAME_KEY + "=" + getTwitterUsername() + "&" + \ + oAuthLibDefaults::OAUTHLIB_SESSIONPASSWORD_KEY + "=" + getTwitterPassword(); + + /* Set OAuth header */ + m_oAuth.getOAuthHeader( eOAuthHttpPost, authorizeUrl, dataStr, oAuthHttpHeader ); + if( oAuthHttpHeader.length() ) + { + pOAuthHeaderList = curl_slist_append( pOAuthHeaderList, oAuthHttpHeader.c_str() ); + if( pOAuthHeaderList ) + { + curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, pOAuthHeaderList ); + } + } + + /* Set http request and url */ + curl_easy_setopt( m_curlHandle, CURLOPT_POST, 1 ); + curl_easy_setopt( m_curlHandle, CURLOPT_URL, authorizeUrl.c_str() ); + curl_easy_setopt( m_curlHandle, CURLOPT_COPYPOSTFIELDS, dataStr.c_str() ); + + /* Send http request */ + if( CURLE_OK == curl_easy_perform( m_curlHandle ) ) + { + if( pOAuthHeaderList ) + { + curl_easy_getinfo( m_curlHandle, CURLINFO_HTTP_CODE, &httpStatusCode ); + curl_slist_free_all( pOAuthHeaderList ); + + // Now, let's find the PIN CODE + nPosStart = m_callbackData.find( oAuthLibDefaults::OAUTHLIB_PIN_TWITTER_RESP_KEY ); + if( std::string::npos == nPosStart ) + { + return false; + } + nPosStart += oAuthLibDefaults::OAUTHLIB_PIN_TWITTER_RESP_KEY.length(); + nPosEnd = m_callbackData.substr( nPosStart ).find( oAuthLibDefaults::OAUTHLIB_PIN_END_TAG_TWITTER_RESP ); + if( std::string::npos == nPosEnd ) + { + return false; + } + pinCodeVal = m_callbackData.substr( nPosStart, nPosEnd ); + getOAuth().setOAuthPin( pinCodeVal ); + return true; + } + } + else if( pOAuthHeaderList ) + { + curl_slist_free_all( pOAuthHeaderList ); + } + return false; +} + diff --git a/backends/twitter/libtwitcurl/twitcurl.dsp b/backends/twitter/libtwitcurl/twitcurl.dsp index 14230b2552f51546df0c3bb42dd71e46a488ddc0..436cb0381fbef92208efb2f1d9b1bd93be4a44cb 100644 --- a/backends/twitter/libtwitcurl/twitcurl.dsp +++ b/backends/twitter/libtwitcurl/twitcurl.dsp @@ -1,140 +1,140 @@ -# Microsoft Developer Studio Project File - Name="twitcurl" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Static Library" 0x0104 - -CFG=twitcurl - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "twitcurl.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "twitcurl.mak" CFG="twitcurl - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "twitcurl - Win32 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "twitcurl - Win32 Debug" (based on "Win32 (x86) Static Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "twitcurl - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "./curl" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo - -!ELSEIF "$(CFG)" == "twitcurl - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "./curl" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo - -!ENDIF - -# Begin Target - -# Name "twitcurl - Win32 Release" -# Name "twitcurl - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\base64.cpp -# End Source File -# Begin Source File - -SOURCE=.\HMAC_SHA1.cpp -# End Source File -# Begin Source File - -SOURCE=.\oauthlib.cpp -# End Source File -# Begin Source File - -SOURCE=.\SHA1.cpp -# End Source File -# Begin Source File - -SOURCE=.\twitcurl.cpp -# End Source File -# Begin Source File - -SOURCE=.\urlencode.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\base64.h -# End Source File -# Begin Source File - -SOURCE=.\HMAC_SHA1.h -# End Source File -# Begin Source File - -SOURCE=.\oauthlib.h -# End Source File -# Begin Source File - -SOURCE=.\SHA1.h -# End Source File -# Begin Source File - -SOURCE=.\twitcurl.h -# End Source File -# Begin Source File - -SOURCE=.\urlencode.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="twitcurl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=twitcurl - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "twitcurl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "twitcurl.mak" CFG="twitcurl - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "twitcurl - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "twitcurl - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "twitcurl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "./curl" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "twitcurl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "./curl" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "twitcurl - Win32 Release" +# Name "twitcurl - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\base64.cpp +# End Source File +# Begin Source File + +SOURCE=.\HMAC_SHA1.cpp +# End Source File +# Begin Source File + +SOURCE=.\oauthlib.cpp +# End Source File +# Begin Source File + +SOURCE=.\SHA1.cpp +# End Source File +# Begin Source File + +SOURCE=.\twitcurl.cpp +# End Source File +# Begin Source File + +SOURCE=.\urlencode.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\base64.h +# End Source File +# Begin Source File + +SOURCE=.\HMAC_SHA1.h +# End Source File +# Begin Source File + +SOURCE=.\oauthlib.h +# End Source File +# Begin Source File + +SOURCE=.\SHA1.h +# End Source File +# Begin Source File + +SOURCE=.\twitcurl.h +# End Source File +# Begin Source File + +SOURCE=.\urlencode.h +# End Source File +# End Group +# End Target +# End Project diff --git a/backends/twitter/libtwitcurl/twitcurl.dsw b/backends/twitter/libtwitcurl/twitcurl.dsw index 10790bd3208d9cf899c3474a7341fc048e56ad5c..6cff2fd55fecfbd62f35089294cb3f14b9302e65 100644 --- a/backends/twitter/libtwitcurl/twitcurl.dsw +++ b/backends/twitter/libtwitcurl/twitcurl.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "twitcurl"=.\twitcurl.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "twitcurl"=.\twitcurl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/backends/twitter/libtwitcurl/twitcurl.h b/backends/twitter/libtwitcurl/twitcurl.h index 5e491088d53acb13e69a74d3b151ca926eb759de..8d18f1665602335237ff75071015727ecb7aa341 100644 --- a/backends/twitter/libtwitcurl/twitcurl.h +++ b/backends/twitter/libtwitcurl/twitcurl.h @@ -1,190 +1,190 @@ -#ifndef _TWITCURL_H_ -#define _TWITCURL_H_ - -#include -#include -#include -#include -#include "oauthlib.h" -#include "curl/curl.h" - -/* Few common types used by twitCurl */ -namespace twitCurlTypes -{ - typedef enum _eTwitCurlApiFormatType - { - eTwitCurlApiFormatJson = 0, - eTwitCurlApiFormatXml, - eTwitCurlApiFormatMax - } eTwitCurlApiFormatType; - - typedef enum _eTwitCurlProtocolType - { - eTwitCurlProtocolHttps = 0, - eTwitCurlProtocolHttp, - eTwitCurlProtocolMax - } eTwitCurlProtocolType; -}; - -/* twitCurl class */ -class twitCurl -{ -public: - twitCurl(); - ~twitCurl(); - - /* Twitter OAuth authorization methods */ - oAuth& getOAuth(); - bool oAuthRequestToken( std::string& authorizeUrl /* out */ ); - bool oAuthAccessToken(); - bool oAuthHandlePIN( const std::string& authorizeUrl /* in */ ); - - /* Twitter login APIs, set once and forget */ - std::string& getTwitterUsername(); - std::string& getTwitterPassword(); - void setTwitterUsername( std::string& userName /* in */ ); - void setTwitterPassword( std::string& passWord /* in */ ); - - /* Twitter search APIs */ - bool search( std::string& searchQuery /* in */, std::string resultCount = "" /* in */ ); - - /* Twitter status APIs */ - bool statusUpdate( std::string& newStatus /* in */, std::string inReplyToStatusId = "" /* in */ ); - bool statusShowById( std::string& statusId /* in */ ); - bool statusDestroyById( std::string& statusId /* in */ ); - bool retweetById( std::string& statusId /* in */ ); - - /* Twitter timeline APIs */ - bool timelineHomeGet( std::string sinceId = "" /* in */ ); - bool timelinePublicGet(); - bool timelineFriendsGet(); - bool timelineUserGet( bool trimUser /* in */, bool includeRetweets /* in */, - unsigned int tweetCount /* in */, - std::string userInfo = "" /* in */, - bool isUserId = false /* in */ ); - bool featuredUsersGet(); - bool mentionsGet( std::string sinceId = "" /* in */ ); - - /* Twitter user APIs */ - bool userLookup( std::vector &userInfo /* in */, bool isUserId = false /* in */ ); - bool userGet( std::string& userInfo /* in */, bool isUserId = false /* in */ ); - bool friendsGet( std::string userInfo = "" /* in */, bool isUserId = false /* in */ ); - bool followersGet( std::string userInfo = "" /* in */, bool isUserId = false /* in */ ); - - /* Twitter direct message APIs */ - bool directMessageGet( std::string sinceId = "" /* in */ ); - bool directMessageSend( std::string& userInfo /* in */, std::string& dMsg /* in */, bool isUserId = false /* in */ ); - bool directMessageGetSent(); - bool directMessageDestroyById( std::string& dMsgId /* in */ ); - - /* Twitter friendships APIs */ - bool friendshipCreate( std::string& userInfo /* in */, bool isUserId = false /* in */ ); - bool friendshipDestroy( std::string& userInfo /* in */, bool isUserId = false /* in */ ); - bool friendshipShow( std::string& userInfo /* in */, bool isUserId = false /* in */ ); - - /* Twitter social graphs APIs */ - bool friendsIdsGet( std::string& nextCursor /* in */, - std::string& userInfo /* in */, bool isUserId = false /* in */ ); - bool followersIdsGet( std::string& nextCursor /* in */, - std::string& userInfo /* in */, bool isUserId = false /* in */ ); - - /* Twitter account APIs */ - bool accountRateLimitGet(); - bool accountVerifyCredGet(); - - /* Twitter favorites APIs */ - bool favoriteGet(); - bool favoriteCreate( std::string& statusId /* in */ ); - bool favoriteDestroy( std::string& statusId /* in */ ); - - /* Twitter block APIs */ - bool blockCreate( std::string& userInfo /* in */ ); - bool blockDestroy( std::string& userInfo /* in */ ); - bool blockListGet( std::string& nextCursor /* in */, - bool includeEntities /* in */, bool skipStatus /* in */ ); - bool blockIdsGet( std::string& nextCursor /* in */, bool stringifyIds /* in */ ); - - /* Twitter search APIs */ - bool savedSearchGet(); - bool savedSearchCreate( std::string& query /* in */ ); - bool savedSearchShow( std::string& searchId /* in */ ); - bool savedSearchDestroy( std::string& searchId /* in */ ); - - /* Twitter trends APIs (JSON) */ - bool trendsGet(); - bool trendsDailyGet(); - bool trendsWeeklyGet(); - bool trendsCurrentGet(); - bool trendsAvailableGet(); - - /* cURL APIs */ - bool isCurlInit(); - void getLastWebResponse( std::string& outWebResp /* out */ ); - void getLastCurlError( std::string& outErrResp /* out */); - - /* Internal cURL related methods */ - int saveLastWebResponse( char*& data, size_t size ); - - /* cURL proxy APIs */ - std::string& getProxyServerIp(); - std::string& getProxyServerPort(); - std::string& getProxyUserName(); - std::string& getProxyPassword(); - void setProxyServerIp( std::string& proxyServerIp /* in */ ); - void setProxyServerPort( std::string& proxyServerPort /* in */ ); - void setProxyUserName( std::string& proxyUserName /* in */ ); - void setProxyPassword( std::string& proxyPassword /* in */ ); - - /* Clones this object */ - twitCurl* clone(); - -private: - /* cURL data */ - CURL* m_curlHandle; - char* m_errorBuffer; - std::string m_callbackData; - - /* cURL flags */ - bool m_curlProxyParamsSet; - bool m_curlLoginParamsSet; - bool m_curlCallbackParamsSet; - - /* cURL proxy data */ - std::string m_proxyServerIp; - std::string m_proxyServerPort; - std::string m_proxyUserName; - std::string m_proxyPassword; - - /* Twitter data */ - std::string m_twitterUsername; - std::string m_twitterPassword; - - /* Twitter API type */ - twitCurlTypes::eTwitCurlApiFormatType m_eApiFormatType; - twitCurlTypes::eTwitCurlProtocolType m_eProtocolType; - - /* OAuth data */ - oAuth m_oAuth; - - /* Private methods */ - void clearCurlCallbackBuffers(); - void prepareCurlProxy(); - void prepareCurlCallback(); - void prepareCurlUserPass(); - void prepareStandardParams(); - bool performGet( const std::string& getUrl ); - bool performGetInternal( const std::string& getUrl, - const std::string& oAuthHttpHeader ); - bool performDelete( const std::string& deleteUrl ); - bool performPost( const std::string& postUrl, std::string dataStr = "" ); - - /* Internal cURL related methods */ - static int curlCallback( char* data, size_t size, size_t nmemb, twitCurl* pTwitCurlObj ); -}; - - -/* Private functions */ -void utilMakeCurlParams( std::string& outStr, std::string& inParam1, std::string& inParam2 ); -void utilMakeUrlForUser( std::string& outUrl, const std::string& baseUrl, std::string& userInfo, bool isUserId ); - -#endif // _TWITCURL_H_ +#ifndef _TWITCURL_H_ +#define _TWITCURL_H_ + +#include +#include +#include +#include +#include "oauthlib.h" +#include "curl/curl.h" + +/* Few common types used by twitCurl */ +namespace twitCurlTypes +{ + typedef enum _eTwitCurlApiFormatType + { + eTwitCurlApiFormatJson = 0, + eTwitCurlApiFormatXml, + eTwitCurlApiFormatMax + } eTwitCurlApiFormatType; + + typedef enum _eTwitCurlProtocolType + { + eTwitCurlProtocolHttps = 0, + eTwitCurlProtocolHttp, + eTwitCurlProtocolMax + } eTwitCurlProtocolType; +}; + +/* twitCurl class */ +class twitCurl +{ +public: + twitCurl(); + ~twitCurl(); + + /* Twitter OAuth authorization methods */ + oAuth& getOAuth(); + bool oAuthRequestToken( std::string& authorizeUrl /* out */ ); + bool oAuthAccessToken(); + bool oAuthHandlePIN( const std::string& authorizeUrl /* in */ ); + + /* Twitter login APIs, set once and forget */ + std::string& getTwitterUsername(); + std::string& getTwitterPassword(); + void setTwitterUsername( std::string& userName /* in */ ); + void setTwitterPassword( std::string& passWord /* in */ ); + + /* Twitter search APIs */ + bool search( std::string& searchQuery /* in */, std::string resultCount = "" /* in */ ); + + /* Twitter status APIs */ + bool statusUpdate( std::string& newStatus /* in */, std::string inReplyToStatusId = "" /* in */ ); + bool statusShowById( std::string& statusId /* in */ ); + bool statusDestroyById( std::string& statusId /* in */ ); + bool retweetById( std::string& statusId /* in */ ); + + /* Twitter timeline APIs */ + bool timelineHomeGet( std::string sinceId = "" /* in */ ); + bool timelinePublicGet(); + bool timelineFriendsGet(); + bool timelineUserGet( bool trimUser /* in */, bool includeRetweets /* in */, + unsigned int tweetCount /* in */, + std::string userInfo = "" /* in */, + bool isUserId = false /* in */ ); + bool featuredUsersGet(); + bool mentionsGet( std::string sinceId = "" /* in */ ); + + /* Twitter user APIs */ + bool userLookup( std::vector &userInfo /* in */, bool isUserId = false /* in */ ); + bool userGet( std::string& userInfo /* in */, bool isUserId = false /* in */ ); + bool friendsGet( std::string userInfo = "" /* in */, bool isUserId = false /* in */ ); + bool followersGet( std::string userInfo = "" /* in */, bool isUserId = false /* in */ ); + + /* Twitter direct message APIs */ + bool directMessageGet( std::string sinceId = "" /* in */ ); + bool directMessageSend( std::string& userInfo /* in */, std::string& dMsg /* in */, bool isUserId = false /* in */ ); + bool directMessageGetSent(); + bool directMessageDestroyById( std::string& dMsgId /* in */ ); + + /* Twitter friendships APIs */ + bool friendshipCreate( std::string& userInfo /* in */, bool isUserId = false /* in */ ); + bool friendshipDestroy( std::string& userInfo /* in */, bool isUserId = false /* in */ ); + bool friendshipShow( std::string& userInfo /* in */, bool isUserId = false /* in */ ); + + /* Twitter social graphs APIs */ + bool friendsIdsGet( std::string& nextCursor /* in */, + std::string& userInfo /* in */, bool isUserId = false /* in */ ); + bool followersIdsGet( std::string& nextCursor /* in */, + std::string& userInfo /* in */, bool isUserId = false /* in */ ); + + /* Twitter account APIs */ + bool accountRateLimitGet(); + bool accountVerifyCredGet(); + + /* Twitter favorites APIs */ + bool favoriteGet(); + bool favoriteCreate( std::string& statusId /* in */ ); + bool favoriteDestroy( std::string& statusId /* in */ ); + + /* Twitter block APIs */ + bool blockCreate( std::string& userInfo /* in */ ); + bool blockDestroy( std::string& userInfo /* in */ ); + bool blockListGet( std::string& nextCursor /* in */, + bool includeEntities /* in */, bool skipStatus /* in */ ); + bool blockIdsGet( std::string& nextCursor /* in */, bool stringifyIds /* in */ ); + + /* Twitter search APIs */ + bool savedSearchGet(); + bool savedSearchCreate( std::string& query /* in */ ); + bool savedSearchShow( std::string& searchId /* in */ ); + bool savedSearchDestroy( std::string& searchId /* in */ ); + + /* Twitter trends APIs (JSON) */ + bool trendsGet(); + bool trendsDailyGet(); + bool trendsWeeklyGet(); + bool trendsCurrentGet(); + bool trendsAvailableGet(); + + /* cURL APIs */ + bool isCurlInit(); + void getLastWebResponse( std::string& outWebResp /* out */ ); + void getLastCurlError( std::string& outErrResp /* out */); + + /* Internal cURL related methods */ + int saveLastWebResponse( char*& data, size_t size ); + + /* cURL proxy APIs */ + std::string& getProxyServerIp(); + std::string& getProxyServerPort(); + std::string& getProxyUserName(); + std::string& getProxyPassword(); + void setProxyServerIp( std::string& proxyServerIp /* in */ ); + void setProxyServerPort( std::string& proxyServerPort /* in */ ); + void setProxyUserName( std::string& proxyUserName /* in */ ); + void setProxyPassword( std::string& proxyPassword /* in */ ); + + /* Clones this object */ + twitCurl* clone(); + +private: + /* cURL data */ + CURL* m_curlHandle; + char* m_errorBuffer; + std::string m_callbackData; + + /* cURL flags */ + bool m_curlProxyParamsSet; + bool m_curlLoginParamsSet; + bool m_curlCallbackParamsSet; + + /* cURL proxy data */ + std::string m_proxyServerIp; + std::string m_proxyServerPort; + std::string m_proxyUserName; + std::string m_proxyPassword; + + /* Twitter data */ + std::string m_twitterUsername; + std::string m_twitterPassword; + + /* Twitter API type */ + twitCurlTypes::eTwitCurlApiFormatType m_eApiFormatType; + twitCurlTypes::eTwitCurlProtocolType m_eProtocolType; + + /* OAuth data */ + oAuth m_oAuth; + + /* Private methods */ + void clearCurlCallbackBuffers(); + void prepareCurlProxy(); + void prepareCurlCallback(); + void prepareCurlUserPass(); + void prepareStandardParams(); + bool performGet( const std::string& getUrl ); + bool performGetInternal( const std::string& getUrl, + const std::string& oAuthHttpHeader ); + bool performDelete( const std::string& deleteUrl ); + bool performPost( const std::string& postUrl, std::string dataStr = "" ); + + /* Internal cURL related methods */ + static int curlCallback( char* data, size_t size, size_t nmemb, twitCurl* pTwitCurlObj ); +}; + + +/* Private functions */ +void utilMakeCurlParams( std::string& outStr, std::string& inParam1, std::string& inParam2 ); +void utilMakeUrlForUser( std::string& outUrl, const std::string& baseUrl, std::string& userInfo, bool isUserId ); + +#endif // _TWITCURL_H_ diff --git a/backends/twitter/libtwitcurl/twitcurl.plg b/backends/twitter/libtwitcurl/twitcurl.plg index 117e130f2ef0ca7e9fdc7dc783ffe977a2ee847f..d975a9abab3e61ffd85649b19300a750e38499d9 100644 --- a/backends/twitter/libtwitcurl/twitcurl.plg +++ b/backends/twitter/libtwitcurl/twitcurl.plg @@ -1,37 +1,37 @@ - - -
-

Build Log

-

---------------------Configuration: twitcurl - Win32 Release-------------------- -

-

Command Lines

-Creating temporary file "C:\DOCUME~1\Mahesh\LOCALS~1\Temp\RSP239.tmp" with contents -[ -/nologo /ML /W3 /GX /O2 /I "./curl" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Fp"Release/twitcurl.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c -"C:\Projects\twitcurl\base64.cpp" -"C:\Projects\twitcurl\HMAC_SHA1.cpp" -"C:\Projects\twitcurl\oauthlib.cpp" -"C:\Projects\twitcurl\SHA1.cpp" -"C:\Projects\twitcurl\twitcurl.cpp" -"C:\Projects\twitcurl\urlencode.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\Mahesh\LOCALS~1\Temp\RSP239.tmp" -Creating command line "link.exe -lib /nologo /out:"Release\twitcurl.lib" .\Release\base64.obj .\Release\HMAC_SHA1.obj .\Release\oauthlib.obj .\Release\SHA1.obj .\Release\twitcurl.obj .\Release\urlencode.obj " -

Output Window

-Compiling... -base64.cpp -HMAC_SHA1.cpp -oauthlib.cpp -SHA1.cpp -twitcurl.cpp -urlencode.cpp -Creating library... - - - -

Results

-twitcurl.lib - 0 error(s), 0 warning(s) -
- - + + +
+

Build Log

+

+--------------------Configuration: twitcurl - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\Mahesh\LOCALS~1\Temp\RSP239.tmp" with contents +[ +/nologo /ML /W3 /GX /O2 /I "./curl" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Fp"Release/twitcurl.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c +"C:\Projects\twitcurl\base64.cpp" +"C:\Projects\twitcurl\HMAC_SHA1.cpp" +"C:\Projects\twitcurl\oauthlib.cpp" +"C:\Projects\twitcurl\SHA1.cpp" +"C:\Projects\twitcurl\twitcurl.cpp" +"C:\Projects\twitcurl\urlencode.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\Mahesh\LOCALS~1\Temp\RSP239.tmp" +Creating command line "link.exe -lib /nologo /out:"Release\twitcurl.lib" .\Release\base64.obj .\Release\HMAC_SHA1.obj .\Release\oauthlib.obj .\Release\SHA1.obj .\Release\twitcurl.obj .\Release\urlencode.obj " +

Output Window

+Compiling... +base64.cpp +HMAC_SHA1.cpp +oauthlib.cpp +SHA1.cpp +twitcurl.cpp +urlencode.cpp +Creating library... + + + +

Results

+twitcurl.lib - 0 error(s), 0 warning(s) +
+ + diff --git a/backends/twitter/libtwitcurl/twitcurl.sln b/backends/twitter/libtwitcurl/twitcurl.sln index b416f7d2b842db03a7c77a30befb832786528f7b..ec9fbc9696158763db82acc26ec99620faed05e8 100644 --- a/backends/twitter/libtwitcurl/twitcurl.sln +++ b/backends/twitter/libtwitcurl/twitcurl.sln @@ -1,20 +1,20 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "twitcurl", "twitcurl.vcproj", "{00175D8C-EA44-48AE-AC59-B3B7BE04E65C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {00175D8C-EA44-48AE-AC59-B3B7BE04E65C}.Debug|Win32.ActiveCfg = Release|Win32 - {00175D8C-EA44-48AE-AC59-B3B7BE04E65C}.Debug|Win32.Build.0 = Release|Win32 - {00175D8C-EA44-48AE-AC59-B3B7BE04E65C}.Release|Win32.ActiveCfg = Release|Win32 - {00175D8C-EA44-48AE-AC59-B3B7BE04E65C}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "twitcurl", "twitcurl.vcproj", "{00175D8C-EA44-48AE-AC59-B3B7BE04E65C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {00175D8C-EA44-48AE-AC59-B3B7BE04E65C}.Debug|Win32.ActiveCfg = Release|Win32 + {00175D8C-EA44-48AE-AC59-B3B7BE04E65C}.Debug|Win32.Build.0 = Release|Win32 + {00175D8C-EA44-48AE-AC59-B3B7BE04E65C}.Release|Win32.ActiveCfg = Release|Win32 + {00175D8C-EA44-48AE-AC59-B3B7BE04E65C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/backends/twitter/libtwitcurl/twitcurl.vcproj b/backends/twitter/libtwitcurl/twitcurl.vcproj index f62da3eb779e8368550f17fefd44e6d8f6dc0095..9de63b2214953a5ee678682ded7912e60b606e9a 100644 --- a/backends/twitter/libtwitcurl/twitcurl.vcproj +++ b/backends/twitter/libtwitcurl/twitcurl.vcproj @@ -1,347 +1,347 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backends/twitter/libtwitcurl/twitcurlurls.h b/backends/twitter/libtwitcurl/twitcurlurls.h index 4f91961dfa3600695207dde9c59275da24b1df83..418151ea45df563d4f80d54eb3c2d6784d8cfb23 100644 --- a/backends/twitter/libtwitcurl/twitcurlurls.h +++ b/backends/twitter/libtwitcurl/twitcurlurls.h @@ -1,156 +1,156 @@ -#ifndef _TWITCURLURLS_H_ -#define _TWITCURLURLS_H_ - -#include -#include - -/* Default values used in twitcurl */ -namespace twitCurlDefaults -{ - /* Constants */ - const int TWITCURL_DEFAULT_BUFFSIZE = 1024; - const std::string TWITCURL_COLON = ":"; - const char TWITCURL_EOS = '\0'; - const unsigned int MAX_TIMELINE_TWEET_COUNT = 200; - - /* Miscellaneous data used to build twitter URLs*/ - const std::string TWITCURL_STATUSSTRING = "status="; - const std::string TWITCURL_TEXTSTRING = "text="; - const std::string TWITCURL_QUERYSTRING = "query="; - const std::string TWITCURL_SEARCHQUERYSTRING = "q="; - const std::string TWITCURL_SCREENNAME = "screen_name="; - const std::string TWITCURL_USERID = "user_id="; - const std::string TWITCURL_EXTENSIONFORMATS[2] = { ".json", - ".xml" - }; - const std::string TWITCURL_PROTOCOLS[2] = { "https://", - "http://" - }; - const std::string TWITCURL_TARGETSCREENNAME = "target_screen_name="; - const std::string TWITCURL_TARGETUSERID = "target_id="; - const std::string TWITCURL_SINCEID = "since_id="; - const std::string TWITCURL_TRIMUSER = "trim_user=true"; - const std::string TWITCURL_INCRETWEETS = "include_rts=true"; - const std::string TWITCURL_COUNT = "count="; - const std::string TWITCURL_NEXT_CURSOR = "cursor="; - const std::string TWITCURL_SKIP_STATUS = "skip_status="; - const std::string TWITCURL_INCLUDE_ENTITIES = "include_entities="; - const std::string TWITCURL_STRINGIFY_IDS = "stringify_ids="; - const std::string TWITCURL_INREPLYTOSTATUSID = "in_reply_to_status_id="; - - /* URL separators */ - const std::string TWITCURL_URL_SEP_AMP = "&"; - const std::string TWITCURL_URL_SEP_QUES = "?"; -}; - -/* Default twitter URLs */ -namespace twitterDefaults -{ - /* Base URL */ - const std::string TWITCURL_BASE_URL = "api.twitter.com/1.1/"; - - /* Search URLs */ - const std::string TWITCURL_SEARCH_URL = TWITCURL_BASE_URL + "search/tweets"; - - /* Status URLs */ - const std::string TWITCURL_STATUSUPDATE_URL = TWITCURL_BASE_URL + "statuses/update"; - const std::string TWITCURL_STATUSSHOW_URL = TWITCURL_BASE_URL + "statuses/show/"; - const std::string TWITCURL_STATUDESTROY_URL = TWITCURL_BASE_URL + "statuses/destroy/"; - const std::string TWITCURL_RETWEET_URL = TWITCURL_BASE_URL + "statuses/retweet/"; - - /* Timeline URLs */ - const std::string TWITCURL_HOME_TIMELINE_URL = TWITCURL_BASE_URL + "statuses/home_timeline"; - const std::string TWITCURL_PUBLIC_TIMELINE_URL = TWITCURL_BASE_URL + "statuses/public_timeline"; - const std::string TWITCURL_FEATURED_USERS_URL = TWITCURL_BASE_URL + "statuses/featured"; - const std::string TWITCURL_FRIENDS_TIMELINE_URL = TWITCURL_BASE_URL + "statuses/friends_timeline"; - const std::string TWITCURL_MENTIONS_URL = TWITCURL_BASE_URL + "statuses/mentions"; - const std::string TWITCURL_USERTIMELINE_URL = TWITCURL_BASE_URL + "statuses/user_timeline"; - - /* Users URLs */ - const std::string TWITCURL_LOOKUPUSERS_URL = TWITCURL_BASE_URL + "users/lookup"; - const std::string TWITCURL_SHOWUSERS_URL = TWITCURL_BASE_URL + "users/show"; - const std::string TWITCURL_SHOWFRIENDS_URL = TWITCURL_BASE_URL + "statuses/friends"; - const std::string TWITCURL_SHOWFOLLOWERS_URL = TWITCURL_BASE_URL + "statuses/followers"; - - /* Direct messages URLs */ - const std::string TWITCURL_DIRECTMESSAGES_URL = TWITCURL_BASE_URL + "direct_messages"; - const std::string TWITCURL_DIRECTMESSAGENEW_URL = TWITCURL_BASE_URL + "direct_messages/new"; - const std::string TWITCURL_DIRECTMESSAGESSENT_URL = TWITCURL_BASE_URL + "direct_messages/sent"; - const std::string TWITCURL_DIRECTMESSAGEDESTROY_URL = TWITCURL_BASE_URL + "direct_messages/destroy/"; - - /* Friendships URLs */ - const std::string TWITCURL_FRIENDSHIPSCREATE_URL = TWITCURL_BASE_URL + "friendships/create"; - const std::string TWITCURL_FRIENDSHIPSDESTROY_URL = TWITCURL_BASE_URL + "friendships/destroy"; - const std::string TWITCURL_FRIENDSHIPSSHOW_URL = TWITCURL_BASE_URL + "friendships/show"; - - /* Social graphs URLs */ - const std::string TWITCURL_FRIENDSIDS_URL = TWITCURL_BASE_URL + "friends/ids"; - const std::string TWITCURL_FOLLOWERSIDS_URL = TWITCURL_BASE_URL + "followers/ids"; - - /* Account URLs */ - const std::string TWITCURL_ACCOUNTRATELIMIT_URL = TWITCURL_BASE_URL + "account/rate_limit_status"; - const std::string TWITCURL_ACCOUNTVERIFYCRED_URL = TWITCURL_BASE_URL + "account/verify_credentials"; - - /* Favorites URLs */ - const std::string TWITCURL_FAVORITESGET_URL = TWITCURL_BASE_URL + "favorites"; - const std::string TWITCURL_FAVORITECREATE_URL = TWITCURL_BASE_URL + "favorites/create/"; - const std::string TWITCURL_FAVORITEDESTROY_URL = TWITCURL_BASE_URL + "favorites/destroy/"; - - /* Block URLs */ - const std::string TWITCURL_BLOCKSCREATE_URL = TWITCURL_BASE_URL + "blocks/create/"; - const std::string TWITCURL_BLOCKSDESTROY_URL = TWITCURL_BASE_URL + "blocks/destroy/"; - const std::string TWITCURL_BLOCKSLIST_URL = TWITCURL_BASE_URL + "blocks/list"; - const std::string TWITCURL_BLOCKSIDS_URL = TWITCURL_BASE_URL + "blocks/ids"; - - /* Saved Search URLs */ - const std::string TWITCURL_SAVEDSEARCHGET_URL = TWITCURL_BASE_URL + "saved_searches"; - const std::string TWITCURL_SAVEDSEARCHSHOW_URL = TWITCURL_BASE_URL + "saved_searches/show/"; - const std::string TWITCURL_SAVEDSEARCHCREATE_URL = TWITCURL_BASE_URL + "saved_searches/create"; - const std::string TWITCURL_SAVEDSEARCHDESTROY_URL = TWITCURL_BASE_URL + "saved_searches/destroy/"; - - /* Trends URLs */ - const std::string TWITCURL_TRENDS_URL = TWITCURL_BASE_URL + "trends"; - const std::string TWITCURL_TRENDSDAILY_URL = TWITCURL_BASE_URL + "trends/daily"; - const std::string TWITCURL_TRENDSCURRENT_URL = TWITCURL_BASE_URL + "trends/current"; - const std::string TWITCURL_TRENDSWEEKLY_URL = TWITCURL_BASE_URL + "trends/weekly"; - const std::string TWITCURL_TRENDSAVAILABLE_URL = TWITCURL_BASE_URL + "trends/available"; - -}; - -namespace oAuthLibDefaults -{ - /* Constants */ - const int OAUTHLIB_BUFFSIZE = 1024; - const int OAUTHLIB_BUFFSIZE_LARGE = 1024; - const std::string OAUTHLIB_CONSUMERKEY_KEY = "oauth_consumer_key"; - const std::string OAUTHLIB_CALLBACK_KEY = "oauth_callback"; - const std::string OAUTHLIB_VERSION_KEY = "oauth_version"; - const std::string OAUTHLIB_SIGNATUREMETHOD_KEY = "oauth_signature_method"; - const std::string OAUTHLIB_SIGNATURE_KEY = "oauth_signature"; - const std::string OAUTHLIB_TIMESTAMP_KEY = "oauth_timestamp"; - const std::string OAUTHLIB_NONCE_KEY = "oauth_nonce"; - const std::string OAUTHLIB_TOKEN_KEY = "oauth_token"; - const std::string OAUTHLIB_TOKENSECRET_KEY = "oauth_token_secret"; - const std::string OAUTHLIB_VERIFIER_KEY = "oauth_verifier"; - const std::string OAUTHLIB_SCREENNAME_KEY = "screen_name"; - const std::string OAUTHLIB_AUTHENTICITY_TOKEN_KEY = "authenticity_token"; - const std::string OAUTHLIB_SESSIONUSERNAME_KEY = "session[username_or_email]"; - const std::string OAUTHLIB_SESSIONPASSWORD_KEY = "session[password]"; - const std::string OAUTHLIB_AUTHENTICITY_TOKEN_TWITTER_RESP_KEY = "authenticity_token\" type=\"hidden\" value=\""; - const std::string OAUTHLIB_TOKEN_TWITTER_RESP_KEY = "oauth_token\" type=\"hidden\" value=\""; - const std::string OAUTHLIB_PIN_TWITTER_RESP_KEY = "code-desc\">"; - const std::string OAUTHLIB_TOKEN_END_TAG_TWITTER_RESP = "\" />"; - const std::string OAUTHLIB_PIN_END_TAG_TWITTER_RESP = ""; - - const std::string OAUTHLIB_AUTHHEADER_STRING = "Authorization: OAuth "; -}; - -namespace oAuthTwitterApiUrls -{ - /* Twitter OAuth API URLs */ - const std::string OAUTHLIB_TWITTER_REQUEST_TOKEN_URL = "api.twitter.com/oauth/request_token"; - const std::string OAUTHLIB_TWITTER_AUTHORIZE_URL = "api.twitter.com/oauth/authorize?oauth_token="; - const std::string OAUTHLIB_TWITTER_ACCESS_TOKEN_URL = "api.twitter.com/oauth/access_token"; -}; - -#endif // _TWITCURLURLS_H_ +#ifndef _TWITCURLURLS_H_ +#define _TWITCURLURLS_H_ + +#include +#include + +/* Default values used in twitcurl */ +namespace twitCurlDefaults +{ + /* Constants */ + const int TWITCURL_DEFAULT_BUFFSIZE = 1024; + const std::string TWITCURL_COLON = ":"; + const char TWITCURL_EOS = '\0'; + const unsigned int MAX_TIMELINE_TWEET_COUNT = 200; + + /* Miscellaneous data used to build twitter URLs*/ + const std::string TWITCURL_STATUSSTRING = "status="; + const std::string TWITCURL_TEXTSTRING = "text="; + const std::string TWITCURL_QUERYSTRING = "query="; + const std::string TWITCURL_SEARCHQUERYSTRING = "q="; + const std::string TWITCURL_SCREENNAME = "screen_name="; + const std::string TWITCURL_USERID = "user_id="; + const std::string TWITCURL_EXTENSIONFORMATS[2] = { ".json", + ".xml" + }; + const std::string TWITCURL_PROTOCOLS[2] = { "https://", + "http://" + }; + const std::string TWITCURL_TARGETSCREENNAME = "target_screen_name="; + const std::string TWITCURL_TARGETUSERID = "target_id="; + const std::string TWITCURL_SINCEID = "since_id="; + const std::string TWITCURL_TRIMUSER = "trim_user=true"; + const std::string TWITCURL_INCRETWEETS = "include_rts=true"; + const std::string TWITCURL_COUNT = "count="; + const std::string TWITCURL_NEXT_CURSOR = "cursor="; + const std::string TWITCURL_SKIP_STATUS = "skip_status="; + const std::string TWITCURL_INCLUDE_ENTITIES = "include_entities="; + const std::string TWITCURL_STRINGIFY_IDS = "stringify_ids="; + const std::string TWITCURL_INREPLYTOSTATUSID = "in_reply_to_status_id="; + + /* URL separators */ + const std::string TWITCURL_URL_SEP_AMP = "&"; + const std::string TWITCURL_URL_SEP_QUES = "?"; +}; + +/* Default twitter URLs */ +namespace twitterDefaults +{ + /* Base URL */ + const std::string TWITCURL_BASE_URL = "api.twitter.com/1.1/"; + + /* Search URLs */ + const std::string TWITCURL_SEARCH_URL = TWITCURL_BASE_URL + "search/tweets"; + + /* Status URLs */ + const std::string TWITCURL_STATUSUPDATE_URL = TWITCURL_BASE_URL + "statuses/update"; + const std::string TWITCURL_STATUSSHOW_URL = TWITCURL_BASE_URL + "statuses/show/"; + const std::string TWITCURL_STATUDESTROY_URL = TWITCURL_BASE_URL + "statuses/destroy/"; + const std::string TWITCURL_RETWEET_URL = TWITCURL_BASE_URL + "statuses/retweet/"; + + /* Timeline URLs */ + const std::string TWITCURL_HOME_TIMELINE_URL = TWITCURL_BASE_URL + "statuses/home_timeline"; + const std::string TWITCURL_PUBLIC_TIMELINE_URL = TWITCURL_BASE_URL + "statuses/public_timeline"; + const std::string TWITCURL_FEATURED_USERS_URL = TWITCURL_BASE_URL + "statuses/featured"; + const std::string TWITCURL_FRIENDS_TIMELINE_URL = TWITCURL_BASE_URL + "statuses/friends_timeline"; + const std::string TWITCURL_MENTIONS_URL = TWITCURL_BASE_URL + "statuses/mentions"; + const std::string TWITCURL_USERTIMELINE_URL = TWITCURL_BASE_URL + "statuses/user_timeline"; + + /* Users URLs */ + const std::string TWITCURL_LOOKUPUSERS_URL = TWITCURL_BASE_URL + "users/lookup"; + const std::string TWITCURL_SHOWUSERS_URL = TWITCURL_BASE_URL + "users/show"; + const std::string TWITCURL_SHOWFRIENDS_URL = TWITCURL_BASE_URL + "statuses/friends"; + const std::string TWITCURL_SHOWFOLLOWERS_URL = TWITCURL_BASE_URL + "statuses/followers"; + + /* Direct messages URLs */ + const std::string TWITCURL_DIRECTMESSAGES_URL = TWITCURL_BASE_URL + "direct_messages"; + const std::string TWITCURL_DIRECTMESSAGENEW_URL = TWITCURL_BASE_URL + "direct_messages/new"; + const std::string TWITCURL_DIRECTMESSAGESSENT_URL = TWITCURL_BASE_URL + "direct_messages/sent"; + const std::string TWITCURL_DIRECTMESSAGEDESTROY_URL = TWITCURL_BASE_URL + "direct_messages/destroy/"; + + /* Friendships URLs */ + const std::string TWITCURL_FRIENDSHIPSCREATE_URL = TWITCURL_BASE_URL + "friendships/create"; + const std::string TWITCURL_FRIENDSHIPSDESTROY_URL = TWITCURL_BASE_URL + "friendships/destroy"; + const std::string TWITCURL_FRIENDSHIPSSHOW_URL = TWITCURL_BASE_URL + "friendships/show"; + + /* Social graphs URLs */ + const std::string TWITCURL_FRIENDSIDS_URL = TWITCURL_BASE_URL + "friends/ids"; + const std::string TWITCURL_FOLLOWERSIDS_URL = TWITCURL_BASE_URL + "followers/ids"; + + /* Account URLs */ + const std::string TWITCURL_ACCOUNTRATELIMIT_URL = TWITCURL_BASE_URL + "account/rate_limit_status"; + const std::string TWITCURL_ACCOUNTVERIFYCRED_URL = TWITCURL_BASE_URL + "account/verify_credentials"; + + /* Favorites URLs */ + const std::string TWITCURL_FAVORITESGET_URL = TWITCURL_BASE_URL + "favorites"; + const std::string TWITCURL_FAVORITECREATE_URL = TWITCURL_BASE_URL + "favorites/create/"; + const std::string TWITCURL_FAVORITEDESTROY_URL = TWITCURL_BASE_URL + "favorites/destroy/"; + + /* Block URLs */ + const std::string TWITCURL_BLOCKSCREATE_URL = TWITCURL_BASE_URL + "blocks/create/"; + const std::string TWITCURL_BLOCKSDESTROY_URL = TWITCURL_BASE_URL + "blocks/destroy/"; + const std::string TWITCURL_BLOCKSLIST_URL = TWITCURL_BASE_URL + "blocks/list"; + const std::string TWITCURL_BLOCKSIDS_URL = TWITCURL_BASE_URL + "blocks/ids"; + + /* Saved Search URLs */ + const std::string TWITCURL_SAVEDSEARCHGET_URL = TWITCURL_BASE_URL + "saved_searches"; + const std::string TWITCURL_SAVEDSEARCHSHOW_URL = TWITCURL_BASE_URL + "saved_searches/show/"; + const std::string TWITCURL_SAVEDSEARCHCREATE_URL = TWITCURL_BASE_URL + "saved_searches/create"; + const std::string TWITCURL_SAVEDSEARCHDESTROY_URL = TWITCURL_BASE_URL + "saved_searches/destroy/"; + + /* Trends URLs */ + const std::string TWITCURL_TRENDS_URL = TWITCURL_BASE_URL + "trends"; + const std::string TWITCURL_TRENDSDAILY_URL = TWITCURL_BASE_URL + "trends/daily"; + const std::string TWITCURL_TRENDSCURRENT_URL = TWITCURL_BASE_URL + "trends/current"; + const std::string TWITCURL_TRENDSWEEKLY_URL = TWITCURL_BASE_URL + "trends/weekly"; + const std::string TWITCURL_TRENDSAVAILABLE_URL = TWITCURL_BASE_URL + "trends/available"; + +}; + +namespace oAuthLibDefaults +{ + /* Constants */ + const int OAUTHLIB_BUFFSIZE = 1024; + const int OAUTHLIB_BUFFSIZE_LARGE = 1024; + const std::string OAUTHLIB_CONSUMERKEY_KEY = "oauth_consumer_key"; + const std::string OAUTHLIB_CALLBACK_KEY = "oauth_callback"; + const std::string OAUTHLIB_VERSION_KEY = "oauth_version"; + const std::string OAUTHLIB_SIGNATUREMETHOD_KEY = "oauth_signature_method"; + const std::string OAUTHLIB_SIGNATURE_KEY = "oauth_signature"; + const std::string OAUTHLIB_TIMESTAMP_KEY = "oauth_timestamp"; + const std::string OAUTHLIB_NONCE_KEY = "oauth_nonce"; + const std::string OAUTHLIB_TOKEN_KEY = "oauth_token"; + const std::string OAUTHLIB_TOKENSECRET_KEY = "oauth_token_secret"; + const std::string OAUTHLIB_VERIFIER_KEY = "oauth_verifier"; + const std::string OAUTHLIB_SCREENNAME_KEY = "screen_name"; + const std::string OAUTHLIB_AUTHENTICITY_TOKEN_KEY = "authenticity_token"; + const std::string OAUTHLIB_SESSIONUSERNAME_KEY = "session[username_or_email]"; + const std::string OAUTHLIB_SESSIONPASSWORD_KEY = "session[password]"; + const std::string OAUTHLIB_AUTHENTICITY_TOKEN_TWITTER_RESP_KEY = "authenticity_token\" type=\"hidden\" value=\""; + const std::string OAUTHLIB_TOKEN_TWITTER_RESP_KEY = "oauth_token\" type=\"hidden\" value=\""; + const std::string OAUTHLIB_PIN_TWITTER_RESP_KEY = "code-desc\">"; + const std::string OAUTHLIB_TOKEN_END_TAG_TWITTER_RESP = "\" />"; + const std::string OAUTHLIB_PIN_END_TAG_TWITTER_RESP = ""; + + const std::string OAUTHLIB_AUTHHEADER_STRING = "Authorization: OAuth "; +}; + +namespace oAuthTwitterApiUrls +{ + /* Twitter OAuth API URLs */ + const std::string OAUTHLIB_TWITTER_REQUEST_TOKEN_URL = "api.twitter.com/oauth/request_token"; + const std::string OAUTHLIB_TWITTER_AUTHORIZE_URL = "api.twitter.com/oauth/authorize?oauth_token="; + const std::string OAUTHLIB_TWITTER_ACCESS_TOKEN_URL = "api.twitter.com/oauth/access_token"; +}; + +#endif // _TWITCURLURLS_H_ diff --git a/backends/twitter/libtwitcurl/urlencode.cpp b/backends/twitter/libtwitcurl/urlencode.cpp index 8a906b25ac4e0de06f3ad8150b6bfaf4f28c4302..59bb146850a796113e17a545e11a31354a4de572 100644 --- a/backends/twitter/libtwitcurl/urlencode.cpp +++ b/backends/twitter/libtwitcurl/urlencode.cpp @@ -1,40 +1,40 @@ -#include "urlencode.h" - -std::string char2hex( char dec ) -{ - char dig1 = (dec&0xF0)>>4; - char dig2 = (dec&0x0F); - if ( 0<= dig1 && dig1<= 9) dig1+=48; //0,48 in ascii - if (10<= dig1 && dig1<=15) dig1+=65-10; //A,65 in ascii - if ( 0<= dig2 && dig2<= 9) dig2+=48; - if (10<= dig2 && dig2<=15) dig2+=65-10; - - std::string r; - r.append( &dig1, 1); - r.append( &dig2, 1); - return r; -} - -std::string urlencode( const std::string &c ) -{ - - std::string escaped; - int max = c.length(); - for(int i=0; i>4; + char dig2 = (dec&0x0F); + if ( 0<= dig1 && dig1<= 9) dig1+=48; //0,48 in ascii + if (10<= dig1 && dig1<=15) dig1+=65-10; //A,65 in ascii + if ( 0<= dig2 && dig2<= 9) dig2+=48; + if (10<= dig2 && dig2<=15) dig2+=65-10; + + std::string r; + r.append( &dig1, 1); + r.append( &dig2, 1); + return r; +} + +std::string urlencode( const std::string &c ) +{ + + std::string escaped; + int max = c.length(); + for(int i=0; i -#include - -std::string char2hex( char dec ); -std::string urlencode( const std::string &c ); - +#ifndef __URLENCODE_H__ +#define __URLENCODE_H__ + +#include +#include + +std::string char2hex( char dec ); +std::string urlencode( const std::string &c ); + #endif // __URLENCODE_H__ \ No newline at end of file diff --git a/cmake_modules/SwiftenConfig.cmake b/cmake_modules/SwiftenConfig.cmake index cd7dbaf94609cc9f9eae3996314b822205fba9c3..e0357c03d961a23deed0b53980525cced761bc60 100644 --- a/cmake_modules/SwiftenConfig.cmake +++ b/cmake_modules/SwiftenConfig.cmake @@ -1,38 +1,45 @@ -FIND_LIBRARY(SWIFTEN_LIBRARY NAMES Swiften Swiften3 HINTS ../lib) -FIND_PATH(SWIFTEN_INCLUDE_DIR NAMES "Swiften/Swiften.h" PATH_SUFFIXES libSwiften Swiften HINTS ../include) - -if( SWIFTEN_LIBRARY AND SWIFTEN_INCLUDE_DIR ) - find_program(SWIFTEN_CONFIG_EXECUTABLE NAMES swiften-config DOC "swiften-config executable" HINTS ../bin) - set( SWIFTEN_CFLAGS "" ) - if (SWIFTEN_CONFIG_EXECUTABLE) - execute_process( - COMMAND ${SWIFTEN_CONFIG_EXECUTABLE} --libs - OUTPUT_VARIABLE SWIFTEN_LIB) - string(REGEX REPLACE "[\r\n]" " " SWIFTEN_LIB ${SWIFTEN_LIB}) - string(REGEX REPLACE " +$" "" SWIFTEN_LIB ${SWIFTEN_LIB}) - string(REGEX REPLACE " " ";" SWIFTEN_LIB ${SWIFTEN_LIB}) - set(SWIFTEN_LIBRARY "") - foreach(f ${SWIFTEN_LIB}) - STRING(SUBSTRING ${f} 0 2 f_out) - STRING(COMPARE EQUAL ${f_out} "/L" IS_PATH) - if(${IS_PATH}) - string(REGEX REPLACE "/LIBPATH:" "" f_replaced "${f}") - message("Added link directory: ${f_replaced}") - link_directories(${f_replaced}) - else() - list(APPEND SWIFTEN_LIBRARY ${f}) - endif() - endforeach(f) - set( SWIFTEN_FOUND 1 ) - else() - message( STATUS "Could NOT find swiften-config" ) - endif() - - if (SWIFTEN_FOUND) - set( SWIFTEN_INCLUDE_DIR ${SWIFTEN_INCLUDE_DIR} ) - message( STATUS "Found libSwiften: ${SWIFTEN_LIBRARY}, ${SWIFTEN_INCLUDE_DIR}") - endif() - -else( SWIFTEN_LIBRARY AND SWIFTEN_INCLUDE_DIR ) - message( STATUS "Could NOT find libSwiften" ) -endif( SWIFTEN_LIBRARY AND SWIFTEN_INCLUDE_DIR ) +FIND_LIBRARY(SWIFTEN_LIBRARY NAMES Swiften Swiften3 HINTS ../lib) +FIND_PATH(SWIFTEN_INCLUDE_DIR NAMES "Swiften/Swiften.h" PATH_SUFFIXES libSwiften Swiften HINTS ../include) + +if( SWIFTEN_LIBRARY AND SWIFTEN_INCLUDE_DIR ) + find_program(SWIFTEN_CONFIG_EXECUTABLE NAMES swiften-config DOC "swiften-config executable" HINTS ../bin) + set( SWIFTEN_CFLAGS "" ) + if (SWIFTEN_CONFIG_EXECUTABLE) + execute_process( + COMMAND ${SWIFTEN_CONFIG_EXECUTABLE} --libs + OUTPUT_VARIABLE SWIFTEN_LIB) + string(REGEX REPLACE "[\r\n]" " " SWIFTEN_LIB ${SWIFTEN_LIB}) + string(REGEX REPLACE " +$" "" SWIFTEN_LIB ${SWIFTEN_LIB}) + set(SWIFTEN_LIBRARY "") + if (APPLE) + string(REGEX MATCHALL "-framework [A-Za-z]+" APPLE_FRAMEWORKS ${SWIFTEN_LIB}) + foreach(framework ${APPLE_FRAMEWORKS}) + list(APPEND SWIFTEN_LIBRARY ${framework} ) + endforeach(framework) + string(REGEX REPLACE "-framework [A-Za-z]+" "" SWIFTEN_LIB ${SWIFTEN_LIB}) + endif(APPLE) + string(REGEX REPLACE " " ";" SWIFTEN_LIB ${SWIFTEN_LIB}) + foreach(f ${SWIFTEN_LIB}) + STRING(SUBSTRING ${f} 0 2 f_out) + STRING(COMPARE EQUAL ${f_out} "/L" IS_PATH) + if(${IS_PATH}) + string(REGEX REPLACE "/LIBPATH:" "" f_replaced "${f}") + message("Added link directory: ${f_replaced}") + link_directories(${f_replaced}) + else() + list(APPEND SWIFTEN_LIBRARY ${f}) + endif() + endforeach(f) + set( SWIFTEN_FOUND 1 ) + else() + message( STATUS "Could NOT find swiften-config" ) + endif() + + if (SWIFTEN_FOUND) + set( SWIFTEN_INCLUDE_DIR ${SWIFTEN_INCLUDE_DIR} ) + message( STATUS "Found libSwiften: ${SWIFTEN_LIBRARY}, ${SWIFTEN_INCLUDE_DIR}") + endif() + +else( SWIFTEN_LIBRARY AND SWIFTEN_INCLUDE_DIR ) + message( STATUS "Could NOT find libSwiften" ) +endif( SWIFTEN_LIBRARY AND SWIFTEN_INCLUDE_DIR ) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index b9a3ba4382e16538c9f36cdc63318db1c61d9d0f..1a79f8054d1726026661f719322dc820b14a548d 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1 +1 @@ -ADD_SUBDIRECTORY(transport) +ADD_SUBDIRECTORY(transport) diff --git a/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.cpp b/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.cpp index a5d46a6b87467563e87d471293f72c3c586a858c..102de374ada93e651fb4b4b466de670608c7b21c 100644 --- a/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.cpp +++ b/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.cpp @@ -1,110 +1,110 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#include "CombinedOutgoingFileTransferManager.h" - -#include - -#include -#include "Swiften/Disco/EntityCapsProvider.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace Swift { - -CombinedOutgoingFileTransferManager::CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, Transport::PresenceOracle *presOracle, SOCKS5BytestreamServer *bytestreamServer) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), presenceOracle(presOracle), bytestreamServer(bytestreamServer) { - idGenerator = new IDGenerator(); -} - -CombinedOutgoingFileTransferManager::~CombinedOutgoingFileTransferManager() { - delete idGenerator; -} - -boost::shared_ptr CombinedOutgoingFileTransferManager::createOutgoingFileTransfer(const JID& from, const JID& receipient, boost::shared_ptr readBytestream, const StreamInitiationFileInfo& fileInfo) { - // check if receipient support Jingle FT - boost::optional fullJID = highestPriorityJIDSupportingJingle(receipient); - if (!fullJID.is_initialized()) { - fullJID = highestPriorityJIDSupportingSI(receipient); - } - else { - JingleSessionImpl::ref jingleSession = boost::make_shared(from, receipient, idGenerator->generateID(), iqRouter); - - //jsManager->getSession(receipient, idGenerator->generateID()); - assert(jingleSession); - jsManager->registerOutgoingSession(from, jingleSession); -#if !HAVE_SWIFTEN_3 - boost::shared_ptr jingleFT = boost::shared_ptr(new OutgoingJingleFileTransfer(jingleSession, remoteFactory, localFactory, iqRouter, idGenerator, from, receipient, readBytestream, fileInfo, bytestreamRegistry, bytestreamProxy)); - return jingleFT; -#endif - } - - if (!fullJID.is_initialized()) { - return boost::shared_ptr(); - } - - // otherwise try SI - boost::shared_ptr jingleFT = boost::shared_ptr(new MyOutgoingSIFileTransfer(idGenerator->generateID(), from, fullJID.get(), fileInfo.getName(), fileInfo.getSize(), fileInfo.getDescription(), readBytestream, iqRouter, bytestreamServer, bytestreamRegistry)); - // else fail - - return jingleFT; -} - -boost::optional CombinedOutgoingFileTransferManager::highestPriorityJIDSupportingJingle(const JID& bareJID) { - JID fullReceipientJID; - int priority = INT_MIN; - - //getAllPresence(bareJID) gives you all presences for the bare JID (i.e. all resources) Remko Tronçon @ 11:11 - std::vector presences = presenceOracle->getAllPresence(bareJID); - - //iterate over them - foreach(Presence::ref pres, presences) { - if (pres->getPriority() > priority) { - // look up caps from the jid - DiscoInfo::ref info = capsProvider->getCaps(pres->getFrom()); - if (info && info->hasFeature(DiscoInfo::JingleFeature) && info->hasFeature(DiscoInfo::JingleFTFeature) && - info->hasFeature(DiscoInfo::JingleTransportsIBBFeature)) { - - priority = pres->getPriority(); - fullReceipientJID = pres->getFrom(); - } - } - } - - return fullReceipientJID.isValid() ? boost::optional(fullReceipientJID) : boost::optional(); -} - -boost::optional CombinedOutgoingFileTransferManager::highestPriorityJIDSupportingSI(const JID& bareJID) { - JID fullReceipientJID; - int priority = INT_MIN; - - //getAllPresence(bareJID) gives you all presences for the bare JID (i.e. all resources) Remko Tronçon @ 11:11 - std::vector presences = presenceOracle->getAllPresence(bareJID); - - //iterate over them - foreach(Presence::ref pres, presences) { - if (pres->getPriority() > priority) { - // look up caps from the jid - DiscoInfo::ref info = capsProvider->getCaps(pres->getFrom()); - if (info && info->hasFeature("http://jabber.org/protocol/si/profile/file-transfer")) { - - priority = pres->getPriority(); - fullReceipientJID = pres->getFrom(); - } - } - } - - return fullReceipientJID.isValid() ? boost::optional(fullReceipientJID) : boost::optional(); -} - -} +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "CombinedOutgoingFileTransferManager.h" + +#include + +#include +#include "Swiften/Disco/EntityCapsProvider.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace Swift { + +CombinedOutgoingFileTransferManager::CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, Transport::PresenceOracle *presOracle, SOCKS5BytestreamServer *bytestreamServer) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), presenceOracle(presOracle), bytestreamServer(bytestreamServer) { + idGenerator = new IDGenerator(); +} + +CombinedOutgoingFileTransferManager::~CombinedOutgoingFileTransferManager() { + delete idGenerator; +} + +boost::shared_ptr CombinedOutgoingFileTransferManager::createOutgoingFileTransfer(const JID& from, const JID& receipient, boost::shared_ptr readBytestream, const StreamInitiationFileInfo& fileInfo) { + // check if receipient support Jingle FT + boost::optional fullJID = highestPriorityJIDSupportingJingle(receipient); + if (!fullJID.is_initialized()) { + fullJID = highestPriorityJIDSupportingSI(receipient); + } + else { + JingleSessionImpl::ref jingleSession = boost::make_shared(from, receipient, idGenerator->generateID(), iqRouter); + + //jsManager->getSession(receipient, idGenerator->generateID()); + assert(jingleSession); + jsManager->registerOutgoingSession(from, jingleSession); +#if !HAVE_SWIFTEN_3 + boost::shared_ptr jingleFT = boost::shared_ptr(new OutgoingJingleFileTransfer(jingleSession, remoteFactory, localFactory, iqRouter, idGenerator, from, receipient, readBytestream, fileInfo, bytestreamRegistry, bytestreamProxy)); + return jingleFT; +#endif + } + + if (!fullJID.is_initialized()) { + return boost::shared_ptr(); + } + + // otherwise try SI + boost::shared_ptr jingleFT = boost::shared_ptr(new MyOutgoingSIFileTransfer(idGenerator->generateID(), from, fullJID.get(), fileInfo.getName(), fileInfo.getSize(), fileInfo.getDescription(), readBytestream, iqRouter, bytestreamServer, bytestreamRegistry)); + // else fail + + return jingleFT; +} + +boost::optional CombinedOutgoingFileTransferManager::highestPriorityJIDSupportingJingle(const JID& bareJID) { + JID fullReceipientJID; + int priority = INT_MIN; + + //getAllPresence(bareJID) gives you all presences for the bare JID (i.e. all resources) Remko Tronçon @ 11:11 + std::vector presences = presenceOracle->getAllPresence(bareJID); + + //iterate over them + foreach(Presence::ref pres, presences) { + if (pres->getPriority() > priority) { + // look up caps from the jid + DiscoInfo::ref info = capsProvider->getCaps(pres->getFrom()); + if (info && info->hasFeature(DiscoInfo::JingleFeature) && info->hasFeature(DiscoInfo::JingleFTFeature) && + info->hasFeature(DiscoInfo::JingleTransportsIBBFeature)) { + + priority = pres->getPriority(); + fullReceipientJID = pres->getFrom(); + } + } + } + + return fullReceipientJID.isValid() ? boost::optional(fullReceipientJID) : boost::optional(); +} + +boost::optional CombinedOutgoingFileTransferManager::highestPriorityJIDSupportingSI(const JID& bareJID) { + JID fullReceipientJID; + int priority = INT_MIN; + + //getAllPresence(bareJID) gives you all presences for the bare JID (i.e. all resources) Remko Tronçon @ 11:11 + std::vector presences = presenceOracle->getAllPresence(bareJID); + + //iterate over them + foreach(Presence::ref pres, presences) { + if (pres->getPriority() > priority) { + // look up caps from the jid + DiscoInfo::ref info = capsProvider->getCaps(pres->getFrom()); + if (info && info->hasFeature("http://jabber.org/protocol/si/profile/file-transfer")) { + + priority = pres->getPriority(); + fullReceipientJID = pres->getFrom(); + } + } + } + + return fullReceipientJID.isValid() ? boost::optional(fullReceipientJID) : boost::optional(); +} + +} diff --git a/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.h b/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.h index 7cef426f68a88f05ec0b8569246c91968a154507..50b1b0adffe500d2f33ac0d02401556df1c10d4f 100644 --- a/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.h +++ b/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.h @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the simplified BSD license. - * See Documentation/Licenses/BSD-simplified.txt for more information. - */ - -#pragma once - -#include -#include - -#include - -#include "transport/presenceoracle.h" -#include -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - -namespace Swift { - -class JingleSessionManager; -class IQRouter; -class EntityCapsProvider; -class RemoteJingleTransportCandidateSelectorFactory; -class LocalJingleTransportCandidateGeneratorFactory; -class OutgoingFileTransfer; -class JID; -class IDGenerator; -class ReadBytestream; -class StreamInitiationFileInfo; -class SOCKS5BytestreamRegistry; -class SOCKS5BytestreamProxy; -class SOCKS5BytestreamServer; -class PresenceOracle; - -class CombinedOutgoingFileTransferManager { -public: - CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, Transport::PresenceOracle* presOracle, SOCKS5BytestreamServer *server); - ~CombinedOutgoingFileTransferManager(); - - boost::shared_ptr createOutgoingFileTransfer(const JID& from, const JID& to, boost::shared_ptr, const StreamInitiationFileInfo&); - -private: - boost::optional highestPriorityJIDSupportingJingle(const JID& bareJID); - boost::optional highestPriorityJIDSupportingSI(const JID& bareJID); - JingleSessionManager* jsManager; - IQRouter* iqRouter; - EntityCapsProvider* capsProvider; - RemoteJingleTransportCandidateSelectorFactory* remoteFactory; - LocalJingleTransportCandidateGeneratorFactory* localFactory; - IDGenerator *idGenerator; - SOCKS5BytestreamRegistry* bytestreamRegistry; - SOCKS5BytestreamProxy* bytestreamProxy; - Transport::PresenceOracle* presenceOracle; - SOCKS5BytestreamServer *bytestreamServer; -}; - -} +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +#include + +#include "transport/presenceoracle.h" +#include +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + +namespace Swift { + +class JingleSessionManager; +class IQRouter; +class EntityCapsProvider; +class RemoteJingleTransportCandidateSelectorFactory; +class LocalJingleTransportCandidateGeneratorFactory; +class OutgoingFileTransfer; +class JID; +class IDGenerator; +class ReadBytestream; +class StreamInitiationFileInfo; +class SOCKS5BytestreamRegistry; +class SOCKS5BytestreamProxy; +class SOCKS5BytestreamServer; +class PresenceOracle; + +class CombinedOutgoingFileTransferManager { +public: + CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, Transport::PresenceOracle* presOracle, SOCKS5BytestreamServer *server); + ~CombinedOutgoingFileTransferManager(); + + boost::shared_ptr createOutgoingFileTransfer(const JID& from, const JID& to, boost::shared_ptr, const StreamInitiationFileInfo&); + +private: + boost::optional highestPriorityJIDSupportingJingle(const JID& bareJID); + boost::optional highestPriorityJIDSupportingSI(const JID& bareJID); + JingleSessionManager* jsManager; + IQRouter* iqRouter; + EntityCapsProvider* capsProvider; + RemoteJingleTransportCandidateSelectorFactory* remoteFactory; + LocalJingleTransportCandidateGeneratorFactory* localFactory; + IDGenerator *idGenerator; + SOCKS5BytestreamRegistry* bytestreamRegistry; + SOCKS5BytestreamProxy* bytestreamProxy; + Transport::PresenceOracle* presenceOracle; + SOCKS5BytestreamServer *bytestreamServer; +}; + +} diff --git a/include/Swiften/FileTransfer/MyOutgoingSIFileTransfer.cpp b/include/Swiften/FileTransfer/MyOutgoingSIFileTransfer.cpp index 023d809693e004de5ef9855e3c3ba963986c2fb6..5f1253ec80fd7be65198620e94cbb167a189399c 100644 --- a/include/Swiften/FileTransfer/MyOutgoingSIFileTransfer.cpp +++ b/include/Swiften/FileTransfer/MyOutgoingSIFileTransfer.cpp @@ -1,118 +1,118 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include - -#include - -#include -#include -#include -#include -#include - -namespace Swift { - -MyOutgoingSIFileTransfer::MyOutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer, SOCKS5BytestreamRegistry* registry) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer), registry(registry) { -} - -void MyOutgoingSIFileTransfer::start() { - StreamInitiation::ref streamInitiation(new StreamInitiation()); - streamInitiation->setID(id); - streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size)); - streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams"); - streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb"); - StreamInitiationRequest::ref request = StreamInitiationRequest::create(from, to, streamInitiation, iqRouter); - request->onResponse.connect(boost::bind(&MyOutgoingSIFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2)); - request->send(); -} - -void MyOutgoingSIFileTransfer::stop() { -} - -void MyOutgoingSIFileTransfer::cancel() { - // TODO -// session->sendTerminate(JinglePayload::Reason::Cancel); - - if (ibbSession) { - ibbSession->stop(); - } -#if !HAVE_SWIFTEN_3 - SOCKS5BytestreamServerSession *serverSession = registry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(id, from, to)); - if (serverSession) { - serverSession->stop(); - } - - onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); -#endif -} - -void MyOutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) { - if (error) { - finish(FileTransferError()); - } - else { - if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") { -#if !HAVE_SWIFTEN_3 - registry->addReadBytestream(SOCKS5BytestreamRegistry::getHostname(id, from, to), bytestream); - socksServer->addReadBytestream(id, from, to, bytestream); -#endif - Bytestreams::ref bytestreams(new Bytestreams()); - bytestreams->setStreamID(id); - HostAddressPort addressPort = socksServer->getAddressPort(); - bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort())); - BytestreamsRequest::ref request = BytestreamsRequest::create(from, to, bytestreams, iqRouter); - request->onResponse.connect(boost::bind(&MyOutgoingSIFileTransfer::handleBytestreamsRequestResponse, this, _1, _2)); - request->send(); - } - else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") { - ibbSession = boost::shared_ptr(new IBBSendSession(id, from, to, bytestream, iqRouter)); - ibbSession->onFinished.connect(boost::bind(&MyOutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); - ibbSession->start(); -#if !HAVE_SWIFTEN_3 - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); -#endif - } - } -} - -void MyOutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) { - if (error) { - finish(FileTransferError()); - return; - } -#if !HAVE_SWIFTEN_3 - SOCKS5BytestreamServerSession *serverSession = registry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(id, from, to)); -// serverSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); -// serverSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); - serverSession->startTransfer(); - onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); -#endif - //socksServer->onTransferFinished.connect(); -} - -void MyOutgoingSIFileTransfer::finish(boost::optional error) { - if (ibbSession) { - ibbSession->onFinished.disconnect(boost::bind(&MyOutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); - ibbSession.reset(); - } -#if !HAVE_SWIFTEN_3 - socksServer->removeReadBytestream(id, from, to); - if(error) { - onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); - } - else { - onStateChange(FileTransfer::State(FileTransfer::State::Finished)); - } -#endif - onFinished(error); -} - -void MyOutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional error) { - finish(error); -} - -} +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace Swift { + +MyOutgoingSIFileTransfer::MyOutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer, SOCKS5BytestreamRegistry* registry) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer), registry(registry) { +} + +void MyOutgoingSIFileTransfer::start() { + StreamInitiation::ref streamInitiation(new StreamInitiation()); + streamInitiation->setID(id); + streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size)); + streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams"); + streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb"); + StreamInitiationRequest::ref request = StreamInitiationRequest::create(from, to, streamInitiation, iqRouter); + request->onResponse.connect(boost::bind(&MyOutgoingSIFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2)); + request->send(); +} + +void MyOutgoingSIFileTransfer::stop() { +} + +void MyOutgoingSIFileTransfer::cancel() { + // TODO +// session->sendTerminate(JinglePayload::Reason::Cancel); + + if (ibbSession) { + ibbSession->stop(); + } +#if !HAVE_SWIFTEN_3 + SOCKS5BytestreamServerSession *serverSession = registry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(id, from, to)); + if (serverSession) { + serverSession->stop(); + } + + onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); +#endif +} + +void MyOutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) { + if (error) { + finish(FileTransferError()); + } + else { + if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") { +#if !HAVE_SWIFTEN_3 + registry->addReadBytestream(SOCKS5BytestreamRegistry::getHostname(id, from, to), bytestream); + socksServer->addReadBytestream(id, from, to, bytestream); +#endif + Bytestreams::ref bytestreams(new Bytestreams()); + bytestreams->setStreamID(id); + HostAddressPort addressPort = socksServer->getAddressPort(); + bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort())); + BytestreamsRequest::ref request = BytestreamsRequest::create(from, to, bytestreams, iqRouter); + request->onResponse.connect(boost::bind(&MyOutgoingSIFileTransfer::handleBytestreamsRequestResponse, this, _1, _2)); + request->send(); + } + else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") { + ibbSession = boost::shared_ptr(new IBBSendSession(id, from, to, bytestream, iqRouter)); + ibbSession->onFinished.connect(boost::bind(&MyOutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); + ibbSession->start(); +#if !HAVE_SWIFTEN_3 + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); +#endif + } + } +} + +void MyOutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) { + if (error) { + finish(FileTransferError()); + return; + } +#if !HAVE_SWIFTEN_3 + SOCKS5BytestreamServerSession *serverSession = registry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(id, from, to)); +// serverSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); +// serverSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + serverSession->startTransfer(); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); +#endif + //socksServer->onTransferFinished.connect(); +} + +void MyOutgoingSIFileTransfer::finish(boost::optional error) { + if (ibbSession) { + ibbSession->onFinished.disconnect(boost::bind(&MyOutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); + ibbSession.reset(); + } +#if !HAVE_SWIFTEN_3 + socksServer->removeReadBytestream(id, from, to); + if(error) { + onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); + } + else { + onStateChange(FileTransfer::State(FileTransfer::State::Finished)); + } +#endif + onFinished(error); +} + +void MyOutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional error) { + finish(error); +} + +} diff --git a/include/Swiften/FileTransfer/MyOutgoingSIFileTransfer.h b/include/Swiften/FileTransfer/MyOutgoingSIFileTransfer.h index 7e35383065529ff40173163228f0144d58028714..b049e8635ffadea5ca7fee347beb4fcb4862ef58 100644 --- a/include/Swiften/FileTransfer/MyOutgoingSIFileTransfer.h +++ b/include/Swiften/FileTransfer/MyOutgoingSIFileTransfer.h @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - -namespace Swift { - class IQRouter; - class SOCKS5BytestreamServer; - class SOCKS5BytestreamRegistry; - - class MyOutgoingSIFileTransfer : public OutgoingFileTransfer { - public: - MyOutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer, SOCKS5BytestreamRegistry* registry); - - virtual void start(); - virtual void stop(); - virtual void cancel(); - - boost::signal&)> onFinished; - - private: - void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref); - void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref); - void finish(boost::optional error); - void handleIBBSessionFinished(boost::optional error); - - private: - std::string id; - JID from; - JID to; - std::string name; - int size; - std::string description; - boost::shared_ptr bytestream; - IQRouter* iqRouter; - SOCKS5BytestreamServer* socksServer; - boost::shared_ptr ibbSession; - SOCKS5BytestreamRegistry *registry; - }; -} +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + +namespace Swift { + class IQRouter; + class SOCKS5BytestreamServer; + class SOCKS5BytestreamRegistry; + + class MyOutgoingSIFileTransfer : public OutgoingFileTransfer { + public: + MyOutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer, SOCKS5BytestreamRegistry* registry); + + virtual void start(); + virtual void stop(); + virtual void cancel(); + + boost::signal&)> onFinished; + + private: + void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref); + void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref); + void finish(boost::optional error); + void handleIBBSessionFinished(boost::optional error); + + private: + std::string id; + JID from; + JID to; + std::string name; + int size; + std::string description; + boost::shared_ptr bytestream; + IQRouter* iqRouter; + SOCKS5BytestreamServer* socksServer; + boost::shared_ptr ibbSession; + SOCKS5BytestreamRegistry *registry; + }; +} diff --git a/include/Swiften/Network/DummyConnectionServer.cpp b/include/Swiften/Network/DummyConnectionServer.cpp index 7250dce3edf07796745807b95b55857ce8a37bcc..e4c8ef2bd44bf3db5c98d16794abe9f9b79158a8 100644 --- a/include/Swiften/Network/DummyConnectionServer.cpp +++ b/include/Swiften/Network/DummyConnectionServer.cpp @@ -25,7 +25,7 @@ void DummyConnectionServer::stop() { } -void DummyConnectionServer::acceptConnection(boost::shared_ptr connection) { +void DummyConnectionServer::acceptConnection(boost::shared_ptr connection) { eventLoop->postEvent( boost::bind(boost::ref(onNewConnection), connection), shared_from_this()); diff --git a/include/Swiften/Network/DummyConnectionServer.h b/include/Swiften/Network/DummyConnectionServer.h index 0e2a141cd18e064870c66a471259f961ac2b04a2..80d341d42ed018d4688c5dadcbf35b1a17871d52 100644 --- a/include/Swiften/Network/DummyConnectionServer.h +++ b/include/Swiften/Network/DummyConnectionServer.h @@ -30,7 +30,11 @@ namespace Swift { return ref(new DummyConnectionServer(eventLoop)); } - void acceptConnection(boost::shared_ptr connection); + void acceptConnection(boost::shared_ptr connection); + + virtual boost::optional tryStart() { + return boost::optional(); + } virtual void start(); virtual void stop(); diff --git a/include/Swiften/Network/DummyNetworkFactories.cpp b/include/Swiften/Network/DummyNetworkFactories.cpp index 28fbe5b0f6b49333295db39b7414bf8467a6f49e..a47ec8fed345cfd451135b5621b74b16d0141662 100644 --- a/include/Swiften/Network/DummyNetworkFactories.cpp +++ b/include/Swiften/Network/DummyNetworkFactories.cpp @@ -9,6 +9,12 @@ #include #include #include +#if HAVE_SWIFTEN_3 +#include +#include +#include +#include +#endif namespace Swift { @@ -18,6 +24,8 @@ DummyNetworkFactories::DummyNetworkFactories(EventLoop* eventLoop) { #if HAVE_SWIFTEN_3 idnConverter = boost::shared_ptr(PlatformIDNConverter::create()); domainNameResolver = new PlatformDomainNameResolver(idnConverter.get(), eventLoop); + cryptoProvider = PlatformCryptoProvider::create(); + networkEnvironment = new PlatformNetworkEnvironment(); #else domainNameResolver = new PlatformDomainNameResolver(eventLoop); #endif diff --git a/include/Swiften/Network/DummyNetworkFactories.h b/include/Swiften/Network/DummyNetworkFactories.h index 78b17f7c66df5ed0b3ae02f3f7f87dc9db2622c3..6637c6b9dfacfbc8596327b84a63c65d3a52bd22 100644 --- a/include/Swiften/Network/DummyNetworkFactories.h +++ b/include/Swiften/Network/DummyNetworkFactories.h @@ -1,80 +1,88 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - -#include -#include -#if HAVE_SWIFTEN_3 -#include -#include -#endif - -namespace Swift { - class EventLoop; - - class DummyNetworkFactories : public NetworkFactories { - public: - DummyNetworkFactories(EventLoop *eventLoop); - ~DummyNetworkFactories(); - - virtual TimerFactory* getTimerFactory() const { - return timerFactory; - } - - virtual ConnectionFactory* getConnectionFactory() const { - return connectionFactory; - } - -#if HAVE_SWIFTEN_3 - IDNConverter* getIDNConverter() const { - return idnConverter.get(); - } -#endif - - DomainNameResolver* getDomainNameResolver() const { - return domainNameResolver; - } - - ConnectionServerFactory* getConnectionServerFactory() const { - return connectionServerFactory; - } - - virtual Swift::NATTraverser* getNATTraverser() const { - return 0; - } - - Swift::XMLParserFactory* getXMLParserFactory() const { - return m_platformXMLParserFactory; - } - - EventLoop *getEventLoop() const { - return eventLoop; - } - - Swift::TLSContextFactory* getTLSContextFactory() const { - return 0; - } - - Swift::ProxyProvider* getProxyProvider() const { - return 0; - } - - private: - PlatformXMLParserFactory *m_platformXMLParserFactory; - TimerFactory* timerFactory; - ConnectionFactory* connectionFactory; -#if HAVE_SWIFTEN_3 - boost::shared_ptr idnConverter; -#endif - DomainNameResolver* domainNameResolver; - ConnectionServerFactory* connectionServerFactory; - EventLoop *eventLoop; - }; -} +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + +#include +#include +#if HAVE_SWIFTEN_3 +#include +#include +#endif + +namespace Swift { + class EventLoop; + + class DummyNetworkFactories : public NetworkFactories { + public: + DummyNetworkFactories(EventLoop *eventLoop); + ~DummyNetworkFactories(); + + virtual TimerFactory* getTimerFactory() const { + return timerFactory; + } + + virtual ConnectionFactory* getConnectionFactory() const { + return connectionFactory; + } + +#if HAVE_SWIFTEN_3 + IDNConverter* getIDNConverter() const { + return idnConverter.get(); + } + Swift::CryptoProvider* getCryptoProvider() const { + return cryptoProvider; + } + Swift::NetworkEnvironment* getNetworkEnvironment() const { + return networkEnvironment; + } + +#endif + + DomainNameResolver* getDomainNameResolver() const { + return domainNameResolver; + } + + ConnectionServerFactory* getConnectionServerFactory() const { + return connectionServerFactory; + } + + virtual Swift::NATTraverser* getNATTraverser() const { + return 0; + } + + Swift::XMLParserFactory* getXMLParserFactory() const { + return m_platformXMLParserFactory; + } + + EventLoop *getEventLoop() const { + return eventLoop; + } + + Swift::TLSContextFactory* getTLSContextFactory() const { + return 0; + } + + Swift::ProxyProvider* getProxyProvider() const { + return 0; + } + private: + PlatformXMLParserFactory *m_platformXMLParserFactory; + TimerFactory* timerFactory; + ConnectionFactory* connectionFactory; +#if HAVE_SWIFTEN_3 + boost::shared_ptr idnConverter; + CryptoProvider* cryptoProvider; + NetworkEnvironment* networkEnvironment; +#endif + DomainNameResolver* domainNameResolver; + ConnectionServerFactory* connectionServerFactory; + EventLoop *eventLoop; + }; +} diff --git a/include/Swiften/Server/ServerFromClientSession.cpp b/include/Swiften/Server/ServerFromClientSession.cpp index 9c61c6a54cd638c0a31be39b0901dcfef647e22c..e6ae808e513a75343df4f151eaf5b75030799a68 100644 --- a/include/Swiften/Server/ServerFromClientSession.cpp +++ b/include/Swiften/Server/ServerFromClientSession.cpp @@ -1,183 +1,183 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Swift { - -ServerFromClientSession::ServerFromClientSession( - const std::string& id, - boost::shared_ptr connection, - PayloadParserFactoryCollection* payloadParserFactories, - PayloadSerializerCollection* payloadSerializers, - UserRegistry* userRegistry, - XMLParserFactory* factory, - Swift::JID remoteJID) : - Session(connection, payloadParserFactories, payloadSerializers, factory), - id_(id), - userRegistry_(userRegistry), - authenticated_(false), - initialized(false), - allowSASLEXTERNAL(false), - tlsLayer(0), - tlsConnected(false) { - setRemoteJID(remoteJID); -} - -ServerFromClientSession::~ServerFromClientSession() { - if (tlsLayer) { - delete tlsLayer; - } -} - -void ServerFromClientSession::handlePasswordValid() { - if (!isInitialized()) { - getXMPPLayer()->writeElement(boost::shared_ptr(new AuthSuccess())); - authenticated_ = true; - getXMPPLayer()->resetParser(); - } -} - -void ServerFromClientSession::handlePasswordInvalid(const std::string &error) { - if (!isInitialized()) { - getXMPPLayer()->writeElement(boost::shared_ptr(new AuthFailure)); - if (!error.empty()) { - boost::shared_ptr msg(new StreamError(StreamError::UndefinedCondition, error)); - getXMPPLayer()->writeElement(msg); - } - - finishSession(AuthenticationFailedError); - } -} - -void ServerFromClientSession::handleElement(boost::shared_ptr element) { - if (isInitialized()) { - onElementReceived(element); - } - else { - if (AuthRequest* authRequest = dynamic_cast(element.get())) { - if (authRequest->getMechanism() == "PLAIN" || (allowSASLEXTERNAL && authRequest->getMechanism() == "EXTERNAL")) { - if (authRequest->getMechanism() == "EXTERNAL") { - getXMPPLayer()->writeElement(boost::shared_ptr(new AuthSuccess())); - authenticated_ = true; - getXMPPLayer()->resetParser(); - } - else { - PLAINMessage plainMessage(authRequest->getMessage() ? *authRequest->getMessage() : createSafeByteArray("")); - user_ = plainMessage.getAuthenticationID(); - userRegistry_->isValidUserPassword(JID(plainMessage.getAuthenticationID(), getLocalJID().getDomain()), this, plainMessage.getPassword()); - } - } - else { - getXMPPLayer()->writeElement(boost::shared_ptr(new AuthFailure)); - finishSession(NoSupportedAuthMechanismsError); - } - } - else if (dynamic_cast(element.get()) != NULL) { - getXMPPLayer()->writeElement(boost::shared_ptr(new TLSProceed)); - getStreamStack()->addLayer(tlsLayer); - tlsLayer->connect(); - getXMPPLayer()->resetParser(); - } - else if (IQ* iq = dynamic_cast(element.get())) { - if (boost::shared_ptr resourceBind = iq->getPayload()) { - std::string bucket = "abcdefghijklmnopqrstuvwxyz"; - std::string uuid; - for (int i = 0; i < 10; i++) { - uuid += bucket[rand() % bucket.size()]; - } - setRemoteJID(JID(user_, getLocalJID().getDomain(), uuid)); - boost::shared_ptr resultResourceBind(new ResourceBind()); - resultResourceBind->setJID(getRemoteJID()); - getXMPPLayer()->writeElement(IQ::createResult(JID(), iq->getID(), resultResourceBind)); - } - else if (iq->getPayload()) { - getXMPPLayer()->writeElement(IQ::createResult(getRemoteJID(), iq->getID())); - setInitialized(); - } - } - } -} - -void ServerFromClientSession::handleStreamStart(const ProtocolHeader& incomingHeader) { - setLocalJID(JID("", incomingHeader.getTo())); - ProtocolHeader header; - header.setFrom(incomingHeader.getTo()); - header.setID(id_); - getXMPPLayer()->writeHeader(header); - - boost::shared_ptr features(new StreamFeatures()); - - if (!authenticated_) { - if (tlsLayer && !tlsConnected) { - features->setHasStartTLS(); - } - features->addAuthenticationMechanism("PLAIN"); - if (allowSASLEXTERNAL) { - features->addAuthenticationMechanism("EXTERNAL"); - } - } - else { - features->setHasResourceBind(); - features->setHasSession(); - } - getXMPPLayer()->writeElement(features); -} - -void ServerFromClientSession::setInitialized() { - initialized = true; - onSessionStarted(); -} - -void ServerFromClientSession::setAllowSASLEXTERNAL() { - allowSASLEXTERNAL = true; -} - -void ServerFromClientSession::handleSessionFinished(const boost::optional&) { - userRegistry_->stopLogin(JID(user_, getLocalJID().getDomain()), this); -} - -void ServerFromClientSession::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, CertificateWithKey::ref cert) { - tlsLayer = new TLSServerLayer(tlsContextFactory); - if (!tlsLayer->setServerCertificate(cert)) { -// std::cout << "error\n"; - // TODO: -// onClosed(boost::shared_ptr(new Error(Error::InvalidTLSCertificateError))); - } - else { - tlsLayer->onError.connect(boost::bind(&ServerFromClientSession::handleTLSError, this)); - tlsLayer->onConnected.connect(boost::bind(&ServerFromClientSession::handleTLSConnected, this)); -// getStreamStack()->addLayer(tlsLayer); -// tlsLayer->onError.connect(boost::bind(&BasicSessionStream::handleTLSError, this)); -// tlsLayer->onConnected.connect(boost::bind(&BasicSessionStream::handleTLSConnected, this)); -// tlsLayer->connect(); - } -} - -} +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Swift { + +ServerFromClientSession::ServerFromClientSession( + const std::string& id, + boost::shared_ptr connection, + PayloadParserFactoryCollection* payloadParserFactories, + PayloadSerializerCollection* payloadSerializers, + UserRegistry* userRegistry, + XMLParserFactory* factory, + Swift::JID remoteJID) : + Session(connection, payloadParserFactories, payloadSerializers, factory), + id_(id), + userRegistry_(userRegistry), + authenticated_(false), + initialized(false), + allowSASLEXTERNAL(false), + tlsLayer(0), + tlsConnected(false) { + setRemoteJID(remoteJID); +} + +ServerFromClientSession::~ServerFromClientSession() { + if (tlsLayer) { + delete tlsLayer; + } +} + +void ServerFromClientSession::handlePasswordValid() { + if (!isInitialized()) { + getXMPPLayer()->writeElement(boost::shared_ptr(new AuthSuccess())); + authenticated_ = true; + getXMPPLayer()->resetParser(); + } +} + +void ServerFromClientSession::handlePasswordInvalid(const std::string &error) { + if (!isInitialized()) { + getXMPPLayer()->writeElement(boost::shared_ptr(new AuthFailure)); + if (!error.empty()) { + boost::shared_ptr msg(new StreamError(StreamError::UndefinedCondition, error)); + getXMPPLayer()->writeElement(msg); + } + + finishSession(AuthenticationFailedError); + } +} + +void ServerFromClientSession::handleElement(boost::shared_ptr element) { + if (isInitialized()) { + onElementReceived(element); + } + else { + if (AuthRequest* authRequest = dynamic_cast(element.get())) { + if (authRequest->getMechanism() == "PLAIN" || (allowSASLEXTERNAL && authRequest->getMechanism() == "EXTERNAL")) { + if (authRequest->getMechanism() == "EXTERNAL") { + getXMPPLayer()->writeElement(boost::shared_ptr(new AuthSuccess())); + authenticated_ = true; + getXMPPLayer()->resetParser(); + } + else { + PLAINMessage plainMessage(authRequest->getMessage() ? *authRequest->getMessage() : createSafeByteArray("")); + user_ = plainMessage.getAuthenticationID(); + userRegistry_->isValidUserPassword(JID(plainMessage.getAuthenticationID(), getLocalJID().getDomain()), this, plainMessage.getPassword()); + } + } + else { + getXMPPLayer()->writeElement(boost::shared_ptr(new AuthFailure)); + finishSession(NoSupportedAuthMechanismsError); + } + } + else if (dynamic_cast(element.get()) != NULL) { + getXMPPLayer()->writeElement(boost::shared_ptr(new TLSProceed)); + getStreamStack()->addLayer(tlsLayer); + tlsLayer->connect(); + getXMPPLayer()->resetParser(); + } + else if (IQ* iq = dynamic_cast(element.get())) { + if (boost::shared_ptr resourceBind = iq->getPayload()) { + std::string bucket = "abcdefghijklmnopqrstuvwxyz"; + std::string uuid; + for (int i = 0; i < 10; i++) { + uuid += bucket[rand() % bucket.size()]; + } + setRemoteJID(JID(user_, getLocalJID().getDomain(), uuid)); + boost::shared_ptr resultResourceBind(new ResourceBind()); + resultResourceBind->setJID(getRemoteJID()); + getXMPPLayer()->writeElement(IQ::createResult(JID(), iq->getID(), resultResourceBind)); + } + else if (iq->getPayload()) { + getXMPPLayer()->writeElement(IQ::createResult(getRemoteJID(), iq->getID())); + setInitialized(); + } + } + } +} + +void ServerFromClientSession::handleStreamStart(const ProtocolHeader& incomingHeader) { + setLocalJID(JID("", incomingHeader.getTo())); + ProtocolHeader header; + header.setFrom(incomingHeader.getTo()); + header.setID(id_); + getXMPPLayer()->writeHeader(header); + + boost::shared_ptr features(new StreamFeatures()); + + if (!authenticated_) { + if (tlsLayer && !tlsConnected) { + features->setHasStartTLS(); + } + features->addAuthenticationMechanism("PLAIN"); + if (allowSASLEXTERNAL) { + features->addAuthenticationMechanism("EXTERNAL"); + } + } + else { + features->setHasResourceBind(); + features->setHasSession(); + } + getXMPPLayer()->writeElement(features); +} + +void ServerFromClientSession::setInitialized() { + initialized = true; + onSessionStarted(); +} + +void ServerFromClientSession::setAllowSASLEXTERNAL() { + allowSASLEXTERNAL = true; +} + +void ServerFromClientSession::handleSessionFinished(const boost::optional&) { + userRegistry_->stopLogin(JID(user_, getLocalJID().getDomain()), this); +} + +void ServerFromClientSession::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, CertificateWithKey::ref cert) { + tlsLayer = new TLSServerLayer(tlsContextFactory); + if (!tlsLayer->setServerCertificate(cert)) { +// std::cout << "error\n"; + // TODO: +// onClosed(boost::shared_ptr(new Error(Error::InvalidTLSCertificateError))); + } + else { + tlsLayer->onError.connect(boost::bind(&ServerFromClientSession::handleTLSError, this)); + tlsLayer->onConnected.connect(boost::bind(&ServerFromClientSession::handleTLSConnected, this)); +// getStreamStack()->addLayer(tlsLayer); +// tlsLayer->onError.connect(boost::bind(&BasicSessionStream::handleTLSError, this)); +// tlsLayer->onConnected.connect(boost::bind(&BasicSessionStream::handleTLSConnected, this)); +// tlsLayer->connect(); + } +} + +} diff --git a/include/Swiften/Server/ServerFromClientSession.h b/include/Swiften/Server/ServerFromClientSession.h index 230bb119fc13ca9153ddbc83e7036cb6b517b2b9..674b54fef0e3041f14b8305a690f1bc11aa13df1 100644 --- a/include/Swiften/Server/ServerFromClientSession.h +++ b/include/Swiften/Server/ServerFromClientSession.h @@ -1,91 +1,91 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - -namespace Swift { - class ProtocolHeader; - class Element; - class Stanza; - class PayloadParserFactoryCollection; - class PayloadSerializerCollection; - class StreamStack; - class UserRegistry; - class XMPPLayer; - class ConnectionLayer; - class Connection; - class TLSServerLayer; - class TLSServerContextFactory; - class PKCS12Certificate; - - class ServerFromClientSession : public Session { - public: - ServerFromClientSession( - const std::string& id, - boost::shared_ptr connection, - PayloadParserFactoryCollection* payloadParserFactories, - PayloadSerializerCollection* payloadSerializers, - UserRegistry* userRegistry, - XMLParserFactory* factory, - Swift::JID remoteJID = Swift::JID()); - ~ServerFromClientSession(); - - boost::signal onSessionStarted; - void setAllowSASLEXTERNAL(); - const std::string &getUser() { - return user_; - } - - void addTLSEncryption(TLSServerContextFactory* tlsContextFactory, CertificateWithKey::ref cert); - - Swift::JID getBareJID() { - return Swift::JID(user_, getLocalJID().getDomain()); - } - - void handlePasswordValid(); - void handlePasswordInvalid(const std::string &error = ""); - - private: -#if HAVE_SWIFTEN_3 - void handleElement(boost::shared_ptr); -#else - void handleElement(boost::shared_ptr); -#endif - void handleStreamStart(const ProtocolHeader& header); - void handleSessionFinished(const boost::optional&); - - void setInitialized(); - bool isInitialized() const { - return initialized; - } - - void handleTLSError() { } - void handleTLSConnected() { tlsConnected = true; } - - private: - std::string id_; - UserRegistry* userRegistry_; - bool authenticated_; - bool initialized; - bool allowSASLEXTERNAL; - std::string user_; - TLSServerLayer* tlsLayer; - bool tlsConnected; - }; -} +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + +namespace Swift { + class ProtocolHeader; + class Element; + class Stanza; + class PayloadParserFactoryCollection; + class PayloadSerializerCollection; + class StreamStack; + class UserRegistry; + class XMPPLayer; + class ConnectionLayer; + class Connection; + class TLSServerLayer; + class TLSServerContextFactory; + class PKCS12Certificate; + + class ServerFromClientSession : public Session { + public: + ServerFromClientSession( + const std::string& id, + boost::shared_ptr connection, + PayloadParserFactoryCollection* payloadParserFactories, + PayloadSerializerCollection* payloadSerializers, + UserRegistry* userRegistry, + XMLParserFactory* factory, + Swift::JID remoteJID = Swift::JID()); + ~ServerFromClientSession(); + + boost::signal onSessionStarted; + void setAllowSASLEXTERNAL(); + const std::string &getUser() { + return user_; + } + + void addTLSEncryption(TLSServerContextFactory* tlsContextFactory, CertificateWithKey::ref cert); + + Swift::JID getBareJID() { + return Swift::JID(user_, getLocalJID().getDomain()); + } + + void handlePasswordValid(); + void handlePasswordInvalid(const std::string &error = ""); + + private: +#if HAVE_SWIFTEN_3 + void handleElement(boost::shared_ptr); +#else + void handleElement(boost::shared_ptr); +#endif + void handleStreamStart(const ProtocolHeader& header); + void handleSessionFinished(const boost::optional&); + + void setInitialized(); + bool isInitialized() const { + return initialized; + } + + void handleTLSError() { } + void handleTLSConnected() { tlsConnected = true; } + + private: + std::string id_; + UserRegistry* userRegistry_; + bool authenticated_; + bool initialized; + bool allowSASLEXTERNAL; + std::string user_; + TLSServerLayer* tlsLayer; + bool tlsConnected; + }; +} diff --git a/include/Swiften/Server/ServerStanzaChannel.cpp b/include/Swiften/Server/ServerStanzaChannel.cpp index af7dc7529ace35dbe7622ca8efcdde1e9b8874ed..d13a0a9b5380832aac84f69ecef041fff5527852 100644 --- a/include/Swiften/Server/ServerStanzaChannel.cpp +++ b/include/Swiften/Server/ServerStanzaChannel.cpp @@ -1,179 +1,179 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swiften/Server/ServerStanzaChannel.h" -#include "Swiften/Base/Error.h" -#include - -#include - -namespace Swift { - -namespace { -// struct PriorityLessThan { -// bool operator()(const ServerSession* s1, const ServerSession* s2) const { -// return s1->getPriority() < s2->getPriority(); -// } -// }; - - struct HasJID { - HasJID(const JID& jid) : jid(jid) {} - bool operator()(const boost::shared_ptr session) const { - return session->getRemoteJID().equals(jid, JID::WithResource); - } - JID jid; - }; -} - -void ServerStanzaChannel::addSession(boost::shared_ptr session) { - sessions[session->getRemoteJID().toBare().toString()].push_back(session); - session->onSessionFinished.connect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); - session->onElementReceived.connect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); - session->onDataRead.connect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session)); -} - -void ServerStanzaChannel::removeSession(boost::shared_ptr session) { - session->onSessionFinished.disconnect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); - session->onElementReceived.disconnect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); - session->onDataRead.disconnect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session)); - std::list > &lst = sessions[session->getRemoteJID().toBare().toString()]; - lst.erase(std::remove(lst.begin(), lst.end(), session), lst.end()); -} - -void ServerStanzaChannel::sendIQ(boost::shared_ptr iq) { - send(iq); -} - -void ServerStanzaChannel::sendMessage(boost::shared_ptr message) { - send(message); -} - -void ServerStanzaChannel::sendPresence(boost::shared_ptr presence) { - send(presence); -} - -void ServerStanzaChannel::handleDataRead(const SafeByteArray &data, const boost::shared_ptr &session) { - if (safeByteArrayToString(data).find("
") != std::string::npos) { - Swift::Presence::ref presence = Swift::Presence::create(); - presence->setFrom(session->getRemoteJID()); - presence->setType(Swift::Presence::Unavailable); - onPresenceReceived(presence); - } -} -#if HAVE_SWIFTEN_3 -void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr element, bool last) { -#else -void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr element, bool last) { -#endif - std::vector > candidateSessions; - for (std::list >::const_iterator i = sessions[to.toBare().toString()].begin(); i != sessions[to.toBare().toString()].end(); ++i) { - candidateSessions.push_back(*i); - } - - for (std::vector >::const_iterator i = candidateSessions.begin(); i != candidateSessions.end(); ++i) { - removeSession(*i); - if (element) { - (*i)->sendElement(element); - } - - if (last && (*i)->getRemoteJID().isValid()) { - Swift::Presence::ref presence = Swift::Presence::create(); - presence->setFrom((*i)->getRemoteJID()); - presence->setType(Swift::Presence::Unavailable); - onPresenceReceived(presence); - } - - (*i)->finishSession(); -// std::cout << "FINISH SESSION " << sessions[to.toBare().toString()].size() << "\n"; - if (last) { - break; - } - } -} - -std::string ServerStanzaChannel::getNewIQID() { - return idGenerator.generateID(); -} - -void ServerStanzaChannel::send(boost::shared_ptr stanza) { - JID to = stanza->getTo(); - assert(to.isValid()); - - // For a full JID, first try to route to a session with the full JID - if (!to.isBare()) { - std::list >::const_iterator i = std::find_if(sessions[stanza->getTo().toBare().toString()].begin(), sessions[stanza->getTo().toBare().toString()].end(), HasJID(to)); - if (i != sessions[stanza->getTo().toBare().toString()].end()) { - (*i)->sendElement(stanza); - return; - } - } - - // Look for candidate sessions - to = to.toBare(); - std::vector > candidateSessions; - for (std::list >::const_iterator i = sessions[stanza->getTo().toBare().toString()].begin(); i != sessions[stanza->getTo().toBare().toString()].end(); ++i) { - if ((*i)->getRemoteJID().equals(to, JID::WithoutResource)) { - candidateSessions.push_back(*i); - (*i)->sendElement(stanza); - } - } - if (candidateSessions.empty()) { - return; - } - - // Find the session with the highest priority -// std::vector::const_iterator i = std::max_element(sessions.begin(), sessions.end(), PriorityLessThan()); -// (*i)->sendStanza(stanza); - return; -} - -void ServerStanzaChannel::handleSessionFinished(const boost::optional&, const boost::shared_ptr& session) { - removeSession(session); - -// if (!session->initiatedFinish()) { - Swift::Presence::ref presence = Swift::Presence::create(); - presence->setFrom(session->getRemoteJID()); - presence->setType(Swift::Presence::Unavailable); - onPresenceReceived(presence); -// } -} - -void ServerStanzaChannel::handleElement(boost::shared_ptr element, const boost::shared_ptr& session) { - boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); - if (!stanza) { - return; - } - - stanza->setFrom(session->getRemoteJID()); - - if (!stanza->getFrom().isValid()) - return; - - - boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); - if (message) { - onMessageReceived(message); - return; - } - - boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); - if (presence) { - onPresenceReceived(presence); - return; - } - - boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); - if (iq) { - onIQReceived(iq); - return; - } -} - -void ServerStanzaChannel::handleSessionInitialized() { - onAvailableChanged(true); -} - -} +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Base/Error.h" +#include + +#include + +namespace Swift { + +namespace { +// struct PriorityLessThan { +// bool operator()(const ServerSession* s1, const ServerSession* s2) const { +// return s1->getPriority() < s2->getPriority(); +// } +// }; + + struct HasJID { + HasJID(const JID& jid) : jid(jid) {} + bool operator()(const boost::shared_ptr session) const { + return session->getRemoteJID().equals(jid, JID::WithResource); + } + JID jid; + }; +} + +void ServerStanzaChannel::addSession(boost::shared_ptr session) { + sessions[session->getRemoteJID().toBare().toString()].push_back(session); + session->onSessionFinished.connect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); + session->onElementReceived.connect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); + session->onDataRead.connect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session)); +} + +void ServerStanzaChannel::removeSession(boost::shared_ptr session) { + session->onSessionFinished.disconnect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); + session->onElementReceived.disconnect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); + session->onDataRead.disconnect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session)); + std::list > &lst = sessions[session->getRemoteJID().toBare().toString()]; + lst.erase(std::remove(lst.begin(), lst.end(), session), lst.end()); +} + +void ServerStanzaChannel::sendIQ(boost::shared_ptr iq) { + send(iq); +} + +void ServerStanzaChannel::sendMessage(boost::shared_ptr message) { + send(message); +} + +void ServerStanzaChannel::sendPresence(boost::shared_ptr presence) { + send(presence); +} + +void ServerStanzaChannel::handleDataRead(const SafeByteArray &data, const boost::shared_ptr &session) { + if (safeByteArrayToString(data).find("
") != std::string::npos) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(session->getRemoteJID()); + presence->setType(Swift::Presence::Unavailable); + onPresenceReceived(presence); + } +} +#if HAVE_SWIFTEN_3 +void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr element, bool last) { +#else +void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr element, bool last) { +#endif + std::vector > candidateSessions; + for (std::list >::const_iterator i = sessions[to.toBare().toString()].begin(); i != sessions[to.toBare().toString()].end(); ++i) { + candidateSessions.push_back(*i); + } + + for (std::vector >::const_iterator i = candidateSessions.begin(); i != candidateSessions.end(); ++i) { + removeSession(*i); + if (element) { + (*i)->sendElement(element); + } + + if (last && (*i)->getRemoteJID().isValid()) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom((*i)->getRemoteJID()); + presence->setType(Swift::Presence::Unavailable); + onPresenceReceived(presence); + } + + (*i)->finishSession(); +// std::cout << "FINISH SESSION " << sessions[to.toBare().toString()].size() << "\n"; + if (last) { + break; + } + } +} + +std::string ServerStanzaChannel::getNewIQID() { + return idGenerator.generateID(); +} + +void ServerStanzaChannel::send(boost::shared_ptr stanza) { + JID to = stanza->getTo(); + assert(to.isValid()); + + // For a full JID, first try to route to a session with the full JID + if (!to.isBare()) { + std::list >::const_iterator i = std::find_if(sessions[stanza->getTo().toBare().toString()].begin(), sessions[stanza->getTo().toBare().toString()].end(), HasJID(to)); + if (i != sessions[stanza->getTo().toBare().toString()].end()) { + (*i)->sendElement(stanza); + return; + } + } + + // Look for candidate sessions + to = to.toBare(); + std::vector > candidateSessions; + for (std::list >::const_iterator i = sessions[stanza->getTo().toBare().toString()].begin(); i != sessions[stanza->getTo().toBare().toString()].end(); ++i) { + if ((*i)->getRemoteJID().equals(to, JID::WithoutResource)) { + candidateSessions.push_back(*i); + (*i)->sendElement(stanza); + } + } + if (candidateSessions.empty()) { + return; + } + + // Find the session with the highest priority +// std::vector::const_iterator i = std::max_element(sessions.begin(), sessions.end(), PriorityLessThan()); +// (*i)->sendStanza(stanza); + return; +} + +void ServerStanzaChannel::handleSessionFinished(const boost::optional&, const boost::shared_ptr& session) { + removeSession(session); + +// if (!session->initiatedFinish()) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(session->getRemoteJID()); + presence->setType(Swift::Presence::Unavailable); + onPresenceReceived(presence); +// } +} + +void ServerStanzaChannel::handleElement(boost::shared_ptr element, const boost::shared_ptr& session) { + boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); + if (!stanza) { + return; + } + + stanza->setFrom(session->getRemoteJID()); + + if (!stanza->getFrom().isValid()) + return; + + + boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); + if (message) { + onMessageReceived(message); + return; + } + + boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); + if (presence) { + onPresenceReceived(presence); + return; + } + + boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); + if (iq) { + onIQReceived(iq); + return; + } +} + +void ServerStanzaChannel::handleSessionInitialized() { + onAvailableChanged(true); +} + +} diff --git a/include/Swiften/Server/ServerStanzaChannel.h b/include/Swiften/Server/ServerStanzaChannel.h index 3b9d45928025dd1b38b5765993ab5d691cda154b..1b26921635466861888bcbb343d83cba5c5edfc0 100644 --- a/include/Swiften/Server/ServerStanzaChannel.h +++ b/include/Swiften/Server/ServerStanzaChannel.h @@ -1,62 +1,62 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include - -#include "Swiften/Base/IDGenerator.h" -#include "Swiften/Server/ServerFromClientSession.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/TLS/Certificate.h" -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - -namespace Swift { - class Error; - class ServerStanzaChannel : public StanzaChannel { - public: - void addSession(boost::shared_ptr session); - void removeSession(boost::shared_ptr session); - - void sendIQ(boost::shared_ptr iq); - void sendMessage(boost::shared_ptr message); - void sendPresence(boost::shared_ptr presence); -#if HAVE_SWIFTEN_3 - void finishSession(const JID& to, boost::shared_ptr element, bool last = false); -#else - void finishSession(const JID& to, boost::shared_ptr element, bool last = false); -#endif - bool getStreamManagementEnabled() const { - return false; - } - - bool isAvailable() const { - return true; - } - - std::vector getPeerCertificateChain() const { - return std::vector(); - } - - private: - std::string getNewIQID(); - void send(boost::shared_ptr stanza); - void handleSessionFinished(const boost::optional&, const boost::shared_ptr &session); - void handleElement(boost::shared_ptr element, const boost::shared_ptr &session); - void handleDataRead(const SafeByteArray &data, const boost::shared_ptr &session); - void handleSessionInitialized(); - - private: - IDGenerator idGenerator; - // [JID][resources][ServerFromClientSession] - std::map > > sessions; - }; - -} +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include + +#include "Swiften/Base/IDGenerator.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Client/StanzaChannel.h" +#include "Swiften/Elements/Message.h" +#include "Swiften/Elements/IQ.h" +#include "Swiften/Elements/Presence.h" +#include "Swiften/TLS/Certificate.h" +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + +namespace Swift { + class Error; + class ServerStanzaChannel : public StanzaChannel { + public: + void addSession(boost::shared_ptr session); + void removeSession(boost::shared_ptr session); + + void sendIQ(boost::shared_ptr iq); + void sendMessage(boost::shared_ptr message); + void sendPresence(boost::shared_ptr presence); +#if HAVE_SWIFTEN_3 + void finishSession(const JID& to, boost::shared_ptr element, bool last = false); +#else + void finishSession(const JID& to, boost::shared_ptr element, bool last = false); +#endif + bool getStreamManagementEnabled() const { + return false; + } + + bool isAvailable() const { + return true; + } + + std::vector getPeerCertificateChain() const { + return std::vector(); + } + + private: + std::string getNewIQID(); + void send(boost::shared_ptr stanza); + void handleSessionFinished(const boost::optional&, const boost::shared_ptr &session); + void handleElement(boost::shared_ptr element, const boost::shared_ptr &session); + void handleDataRead(const SafeByteArray &data, const boost::shared_ptr &session); + void handleSessionInitialized(); + + private: + IDGenerator idGenerator; + // [JID][resources][ServerFromClientSession] + std::map > > sessions; + }; + +} diff --git a/include/transport/filetransfermanager.h b/include/transport/filetransfermanager.h index cc4714a8e1fe99b9b7f3100308e64a161a2290eb..cd0e281cd7b66ab1b03205d101a2d8d6b606ad01 100644 --- a/include/transport/filetransfermanager.h +++ b/include/transport/filetransfermanager.h @@ -1,83 +1,83 @@ -/** - * libtransport -- C++ library for easy XMPP Transports development - * - * Copyright (C) 2011, Jan Kaluza - * - * 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 02111-1301 USA - */ - -#pragma once -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 -#include -#if !HAVE_SWIFTEN_3 -#include -#endif -#include -#include -#if !HAVE_SWIFTEN_3 -#include -#include -#else -#include -#include -#endif -#include -#include -#if !HAVE_SWIFTEN_3 -#include -#endif - -namespace Transport { - -class UserManager; -class User; -class Component; -class Buddy; - -class FileTransferManager { - public: - typedef struct Transfer { - boost::shared_ptr ft; - Swift::JID from; - Swift::JID to; - boost::shared_ptr readByteStream; - } Transfer; - - FileTransferManager(Component *component, UserManager *userManager); - virtual ~FileTransferManager(); - - FileTransferManager::Transfer sendFile(User *user, Buddy *buddy, boost::shared_ptr byteStream, const Swift::StreamInitiationFileInfo &info); - - private: - Component *m_component; - UserManager *m_userManager; - Swift::CombinedOutgoingFileTransferManager* m_outgoingFTManager; - Swift::RemoteJingleTransportCandidateSelectorFactory* m_remoteCandidateSelectorFactory; - Swift::LocalJingleTransportCandidateGeneratorFactory* m_localCandidateGeneratorFactory; - Swift::JingleSessionManager *m_jingleSessionManager; - Swift::SOCKS5BytestreamRegistry* m_bytestreamRegistry; -#if HAVE_SWIFTEN_3 - Swift::SOCKS5BytestreamServerManager* m_proxyServerManager; - Swift::SOCKS5BytestreamProxiesManager *m_proxyManager; -#else - Swift::SOCKS5BytestreamServer* m_bytestreamServer; - Swift::SOCKS5BytestreamProxy* m_bytestreamProxy; - Swift::SOCKS5BytestreamServer *bytestreamServer; - Swift::ConnectivityManager* m_connectivityManager; -#endif -}; - -} +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * 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 02111-1301 USA + */ + +#pragma once +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 +#include +#if !HAVE_SWIFTEN_3 +#include +#endif +#include +#include +#if !HAVE_SWIFTEN_3 +#include +#include +#else +#include +#include +#endif +#include +#include +#if !HAVE_SWIFTEN_3 +#include +#endif + +namespace Transport { + +class UserManager; +class User; +class Component; +class Buddy; + +class FileTransferManager { + public: + typedef struct Transfer { + boost::shared_ptr ft; + Swift::JID from; + Swift::JID to; + boost::shared_ptr readByteStream; + } Transfer; + + FileTransferManager(Component *component, UserManager *userManager); + virtual ~FileTransferManager(); + + FileTransferManager::Transfer sendFile(User *user, Buddy *buddy, boost::shared_ptr byteStream, const Swift::StreamInitiationFileInfo &info); + + private: + Component *m_component; + UserManager *m_userManager; + Swift::CombinedOutgoingFileTransferManager* m_outgoingFTManager; + Swift::RemoteJingleTransportCandidateSelectorFactory* m_remoteCandidateSelectorFactory; + Swift::LocalJingleTransportCandidateGeneratorFactory* m_localCandidateGeneratorFactory; + Swift::JingleSessionManager *m_jingleSessionManager; + Swift::SOCKS5BytestreamRegistry* m_bytestreamRegistry; +#if HAVE_SWIFTEN_3 + Swift::SOCKS5BytestreamServerManager* m_proxyServerManager; + Swift::SOCKS5BytestreamProxiesManager *m_proxyManager; +#else + Swift::SOCKS5BytestreamServer* m_bytestreamServer; + Swift::SOCKS5BytestreamProxy* m_bytestreamProxy; + Swift::SOCKS5BytestreamServer *bytestreamServer; + Swift::ConnectivityManager* m_connectivityManager; +#endif +}; + +} diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index 3230ddb6f726a2e99181a92fa6b0f79a29bdb255..1b1c6f08b03d45c3a240201d81cb91d46ca8ea83 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -21,6 +21,7 @@ #pragma once #include +#undef TYPE_BOOL #include "transport/protocol.pb.h" // #include "conversation.h" #include diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 0c5d1160ca2abe0d9312f80014bc871c3a8db4c7..6c64d00228063be1a04e5d4979b4b1b534f02fef 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -1,199 +1,199 @@ -/** - * libtransport -- C++ library for easy XMPP Transports development - * - * Copyright (C) 2011, Jan Kaluza - * - * 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 02111-1301 USA - */ - -#pragma once - -#include -#include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Disco/EntityCapsManager.h" -#include "Swiften/Network/BoostConnectionServer.h" -#include "Swiften/Network/Connection.h" -#include "Swiften/Elements/ChatState.h" -#include "Swiften/Elements/RosterItemPayload.h" -#include "Swiften/Elements/VCard.h" -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" -#include "Swiften/Parser/XMPPParser.h" -#include "Swiften/Parser/XMPPParserClient.h" -#include "Swiften/Serializer/XMPPSerializer.h" -#include "storagebackend.h" -#include "transport/filetransfermanager.h" -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - -namespace Transport { - -class UserManager; -class User; -class Component; -class Buddy; -class LocalBuddy; -class Config; -class NetworkConversation; -class VCardResponder; -class RosterResponder; -class BlockResponder; -class DummyReadBytestream; -class AdminInterface; -class DiscoItemsResponder; - -class NetworkPluginServer : Swift::XMPPParserClient { - public: - struct Backend { - int pongReceived; - std::list users; - Swift::SafeByteArray data; - boost::shared_ptr connection; - unsigned long res; - unsigned long init_res; - unsigned long shared; - bool acceptUsers; - bool longRun; - bool willDie; - std::string id; - }; - - NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager, DiscoItemsResponder *discoItemsResponder); - - virtual ~NetworkPluginServer(); - - void start(); - - void setAdminInterface(AdminInterface *adminInterface) { - m_adminInterface = adminInterface; - } - - int getBackendCount() { - return m_clients.size(); - } - - const std::list &getBackends() { - return m_clients; - } - - const std::vector &getCrashedBackends() { - return m_crashedBackends; - } - - void collectBackend(); - - bool moveToLongRunBackend(User *user); - - void handleMessageReceived(NetworkConversation *conv, boost::shared_ptr &message); - - public: - void handleNewClientConnection(boost::shared_ptr c); - void handleSessionFinished(Backend *c); - void handlePongReceived(Backend *c); - void handleDataRead(Backend *c, boost::shared_ptr data); - - void handleConnectedPayload(const std::string &payload); - void handleDisconnectedPayload(const std::string &payload); - void handleBuddyChangedPayload(const std::string &payload); - void handleBuddyRemovedPayload(const std::string &payload); - void handleConvMessagePayload(const std::string &payload, bool subject = false); - void handleConvMessageAckPayload(const std::string &payload); - void handleParticipantChangedPayload(const std::string &payload); - void handleRoomChangedPayload(const std::string &payload); - void handleVCardPayload(const std::string &payload); - void handleChatStatePayload(const std::string &payload, Swift::ChatState::ChatStateType type); - void handleAuthorizationPayload(const std::string &payload); - void handleAttentionPayload(const std::string &payload); - void handleStatsPayload(Backend *c, const std::string &payload); - void handleFTStartPayload(const std::string &payload); - void handleFTFinishPayload(const std::string &payload); - void handleFTDataPayload(Backend *b, const std::string &payload); - void handleQueryPayload(Backend *b, const std::string &payload); - void handleBackendConfigPayload(const std::string &payload); - void handleRoomListPayload(const std::string &payload); - void handleRawXML(const std::string &xml); - - void handleUserCreated(User *user); - void handleRoomJoined(User *user, const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password); - void handleRoomLeft(User *user, const std::string &room); - void handleUserReadyToConnect(User *user); - void handleUserPresenceChanged(User *user, Swift::Presence::ref presence); - void handleUserDestroyed(User *user); - - void handleBuddyUpdated(Buddy *buddy, const Swift::RosterItemPayload &item); - void handleBuddyRemoved(Buddy *buddy); - void handleBuddyAdded(Buddy *buddy, const Swift::RosterItemPayload &item); - void handleUserBuddyAdded(User *user, Buddy *buddy); - void handleUserBuddyRemoved(User *user, Buddy *buddy); - - void handleBlockToggled(Buddy *buddy); - - void handleVCardUpdated(User *user, boost::shared_ptr vcard); - void handleVCardRequired(User *user, const std::string &name, unsigned int id); - - void handleFTStateChanged(Swift::FileTransfer::State state, const std::string &userName, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long id); - void handleFTAccepted(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID); - void handleFTRejected(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size); - void handleFTDataNeeded(Backend *b, unsigned long ftid); - - void handlePIDTerminated(unsigned long pid); - private: - void send(boost::shared_ptr &, const std::string &data); - - void pingTimeout(); - void sendPing(Backend *c); - Backend *getFreeClient(bool acceptUsers = true, bool longRun = false, bool check = false); - void connectWaitingUsers(); - void loginDelayFinished(); - void handleRawIQReceived(boost::shared_ptr iq); - void handleRawPresenceReceived(boost::shared_ptr presence); - - void handleStreamStart(const Swift::ProtocolHeader&) {} -#if HAVE_SWIFTEN_3 - void handleElement(boost::shared_ptr element); -#else - void handleElement(boost::shared_ptr element); -#endif - void handleStreamEnd() {} - - UserManager *m_userManager; - VCardResponder *m_vcardResponder; - RosterResponder *m_rosterResponder; - BlockResponder *m_blockResponder; - Config *m_config; - boost::shared_ptr m_server; - std::list m_clients; - std::vector m_pids; - Swift::Timer::ref m_pingTimer; - Swift::Timer::ref m_collectTimer; - Swift::Timer::ref m_loginTimer; - Component *m_component; - std::list m_waitingUsers; - bool m_isNextLongRun; - std::map m_filetransfers; - FileTransferManager *m_ftManager; - std::vector m_crashedBackends; - AdminInterface *m_adminInterface; - bool m_startingBackend; - DiscoItemsResponder *m_discoItemsResponder; - time_t m_lastLogin; - Swift::XMPPParser *m_xmppParser; - Swift::FullPayloadParserFactoryCollection m_collection; - Swift::XMPPSerializer *m_serializer; - Swift::FullPayloadSerializerCollection m_collection2; - std::map m_id2resource; -}; - -} +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * 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 02111-1301 USA + */ + +#pragma once + +#include +#include "Swiften/Presence/PresenceOracle.h" +#include "Swiften/Disco/EntityCapsManager.h" +#include "Swiften/Network/BoostConnectionServer.h" +#include "Swiften/Network/Connection.h" +#include "Swiften/Elements/ChatState.h" +#include "Swiften/Elements/RosterItemPayload.h" +#include "Swiften/Elements/VCard.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" +#include "Swiften/Parser/XMPPParser.h" +#include "Swiften/Parser/XMPPParserClient.h" +#include "Swiften/Serializer/XMPPSerializer.h" +#include "storagebackend.h" +#include "transport/filetransfermanager.h" +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + +namespace Transport { + +class UserManager; +class User; +class Component; +class Buddy; +class LocalBuddy; +class Config; +class NetworkConversation; +class VCardResponder; +class RosterResponder; +class BlockResponder; +class DummyReadBytestream; +class AdminInterface; +class DiscoItemsResponder; + +class NetworkPluginServer : Swift::XMPPParserClient { + public: + struct Backend { + int pongReceived; + std::list users; + Swift::SafeByteArray data; + boost::shared_ptr connection; + unsigned long res; + unsigned long init_res; + unsigned long shared; + bool acceptUsers; + bool longRun; + bool willDie; + std::string id; + }; + + NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager, DiscoItemsResponder *discoItemsResponder); + + virtual ~NetworkPluginServer(); + + void start(); + + void setAdminInterface(AdminInterface *adminInterface) { + m_adminInterface = adminInterface; + } + + int getBackendCount() { + return m_clients.size(); + } + + const std::list &getBackends() { + return m_clients; + } + + const std::vector &getCrashedBackends() { + return m_crashedBackends; + } + + void collectBackend(); + + bool moveToLongRunBackend(User *user); + + void handleMessageReceived(NetworkConversation *conv, boost::shared_ptr &message); + + public: + void handleNewClientConnection(boost::shared_ptr c); + void handleSessionFinished(Backend *c); + void handlePongReceived(Backend *c); + void handleDataRead(Backend *c, boost::shared_ptr data); + + void handleConnectedPayload(const std::string &payload); + void handleDisconnectedPayload(const std::string &payload); + void handleBuddyChangedPayload(const std::string &payload); + void handleBuddyRemovedPayload(const std::string &payload); + void handleConvMessagePayload(const std::string &payload, bool subject = false); + void handleConvMessageAckPayload(const std::string &payload); + void handleParticipantChangedPayload(const std::string &payload); + void handleRoomChangedPayload(const std::string &payload); + void handleVCardPayload(const std::string &payload); + void handleChatStatePayload(const std::string &payload, Swift::ChatState::ChatStateType type); + void handleAuthorizationPayload(const std::string &payload); + void handleAttentionPayload(const std::string &payload); + void handleStatsPayload(Backend *c, const std::string &payload); + void handleFTStartPayload(const std::string &payload); + void handleFTFinishPayload(const std::string &payload); + void handleFTDataPayload(Backend *b, const std::string &payload); + void handleQueryPayload(Backend *b, const std::string &payload); + void handleBackendConfigPayload(const std::string &payload); + void handleRoomListPayload(const std::string &payload); + void handleRawXML(const std::string &xml); + + void handleUserCreated(User *user); + void handleRoomJoined(User *user, const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password); + void handleRoomLeft(User *user, const std::string &room); + void handleUserReadyToConnect(User *user); + void handleUserPresenceChanged(User *user, Swift::Presence::ref presence); + void handleUserDestroyed(User *user); + + void handleBuddyUpdated(Buddy *buddy, const Swift::RosterItemPayload &item); + void handleBuddyRemoved(Buddy *buddy); + void handleBuddyAdded(Buddy *buddy, const Swift::RosterItemPayload &item); + void handleUserBuddyAdded(User *user, Buddy *buddy); + void handleUserBuddyRemoved(User *user, Buddy *buddy); + + void handleBlockToggled(Buddy *buddy); + + void handleVCardUpdated(User *user, boost::shared_ptr vcard); + void handleVCardRequired(User *user, const std::string &name, unsigned int id); + + void handleFTStateChanged(Swift::FileTransfer::State state, const std::string &userName, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long id); + void handleFTAccepted(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID); + void handleFTRejected(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size); + void handleFTDataNeeded(Backend *b, unsigned long ftid); + + void handlePIDTerminated(unsigned long pid); + private: + void send(boost::shared_ptr &, const std::string &data); + + void pingTimeout(); + void sendPing(Backend *c); + Backend *getFreeClient(bool acceptUsers = true, bool longRun = false, bool check = false); + void connectWaitingUsers(); + void loginDelayFinished(); + void handleRawIQReceived(boost::shared_ptr iq); + void handleRawPresenceReceived(boost::shared_ptr presence); + + void handleStreamStart(const Swift::ProtocolHeader&) {} +#if HAVE_SWIFTEN_3 + void handleElement(boost::shared_ptr element); +#else + void handleElement(boost::shared_ptr element); +#endif + void handleStreamEnd() {} + + UserManager *m_userManager; + VCardResponder *m_vcardResponder; + RosterResponder *m_rosterResponder; + BlockResponder *m_blockResponder; + Config *m_config; + boost::shared_ptr m_server; + std::list m_clients; + std::vector m_pids; + Swift::Timer::ref m_pingTimer; + Swift::Timer::ref m_collectTimer; + Swift::Timer::ref m_loginTimer; + Component *m_component; + std::list m_waitingUsers; + bool m_isNextLongRun; + std::map m_filetransfers; + FileTransferManager *m_ftManager; + std::vector m_crashedBackends; + AdminInterface *m_adminInterface; + bool m_startingBackend; + DiscoItemsResponder *m_discoItemsResponder; + time_t m_lastLogin; + Swift::XMPPParser *m_xmppParser; + Swift::FullPayloadParserFactoryCollection m_collection; + Swift::XMPPSerializer *m_serializer; + Swift::FullPayloadSerializerCollection m_collection2; + std::map m_id2resource; +}; + +} diff --git a/include/transport/settingsadhoccommand.h b/include/transport/settingsadhoccommand.h index 9e2708c0053b3545ca6e7dcc826810733acb733f..94611dd49f8f28aaac2564091aae8d87849088a3 100644 --- a/include/transport/settingsadhoccommand.h +++ b/include/transport/settingsadhoccommand.h @@ -1,77 +1,77 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * 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 02111-1301 USA - */ - -#pragma once - -#include -#include -#include -#include "transport/adhoccommand.h" -#include "transport/adhoccommandfactory.h" -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - - -namespace Transport { - -class Component; -class UserManager; -class StorageBackend; - -class SettingsAdHocCommand : public AdHocCommand { - public: - typedef enum { Init, WaitingForResponse } State; - - SettingsAdHocCommand(Component *component, UserManager *userManager, StorageBackend *storageBackend, const Swift::JID &initiator, const Swift::JID &to); - - /// Destructor. - virtual ~SettingsAdHocCommand(); - - virtual boost::shared_ptr handleRequest(boost::shared_ptr payload); - - private: - boost::shared_ptr getForm(); - boost::shared_ptr handleResponse(boost::shared_ptr payload); - State m_state; -}; - -class SettingsAdHocCommandFactory : public AdHocCommandFactory { - public: - SettingsAdHocCommandFactory() { - m_userSettings["send_headlines"] = "0"; - m_userSettings["stay_connected"] = "0"; - } - - virtual ~SettingsAdHocCommandFactory() {} - - AdHocCommand *createAdHocCommand(Component *component, UserManager *userManager, StorageBackend *storageBackend, const Swift::JID &initiator, const Swift::JID &to) { - return new SettingsAdHocCommand(component, userManager, storageBackend, initiator, to); - } - - std::string getNode() { - return "settings"; - } - - std::string getName() { - return "Transport settings"; - } -}; - -} +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * 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 02111-1301 USA + */ + +#pragma once + +#include +#include +#include +#include "transport/adhoccommand.h" +#include "transport/adhoccommandfactory.h" +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + + +namespace Transport { + +class Component; +class UserManager; +class StorageBackend; + +class SettingsAdHocCommand : public AdHocCommand { + public: + typedef enum { Init, WaitingForResponse } State; + + SettingsAdHocCommand(Component *component, UserManager *userManager, StorageBackend *storageBackend, const Swift::JID &initiator, const Swift::JID &to); + + /// Destructor. + virtual ~SettingsAdHocCommand(); + + virtual boost::shared_ptr handleRequest(boost::shared_ptr payload); + + private: + boost::shared_ptr getForm(); + boost::shared_ptr handleResponse(boost::shared_ptr payload); + State m_state; +}; + +class SettingsAdHocCommandFactory : public AdHocCommandFactory { + public: + SettingsAdHocCommandFactory() { + m_userSettings["send_headlines"] = "0"; + m_userSettings["stay_connected"] = "0"; + } + + virtual ~SettingsAdHocCommandFactory() {} + + AdHocCommand *createAdHocCommand(Component *component, UserManager *userManager, StorageBackend *storageBackend, const Swift::JID &initiator, const Swift::JID &to) { + return new SettingsAdHocCommand(component, userManager, storageBackend, initiator, to); + } + + std::string getNode() { + return "settings"; + } + + std::string getName() { + return "Transport settings"; + } +}; + +} diff --git a/include/transport/userregistration.h b/include/transport/userregistration.h index d5fb863317a4d78b31063ca7431e0a6474a85765..c73d0c25162f6517a113141456e92379d0798db4 100644 --- a/include/transport/userregistration.h +++ b/include/transport/userregistration.h @@ -1,87 +1,87 @@ -/** - * libtransport -- C++ library for easy XMPP Transports development - * - * Copyright (C) 2011, Jan Kaluza - * - * 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 02111-1301 USA - */ - -#pragma once - -#include "Swiften/Queries/Responder.h" -#include "Swiften/Elements/InBandRegistrationPayload.h" -#include "Swiften/Elements/RosterPayload.h" -#include -#include -#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 - -namespace Transport { - -struct UserInfo; -class Component; -class StorageBackend; -class UserManager; -class Config; - -/// Allows users to register the transport using service discovery. -class UserRegistration : public Swift::Responder { - public: - /// Creates new UserRegistration handler. - /// \param component Component associated with this class - /// \param userManager UserManager associated with this class - /// \param storageBackend StorageBackend where the registered users will be stored - UserRegistration(Component *component, UserManager *userManager, StorageBackend *storageBackend); - - /// Destroys UserRegistration. - ~UserRegistration(); - - /// Registers new user. This function stores user into database and subscribe user to transport. - /// \param userInfo UserInfo struct with informations about registered user - /// \return false if user is already registered - bool registerUser(const UserInfo &userInfo); - - /// Unregisters user. This function removes all data about user from databa, unsubscribe all buddies - /// managed by this transport and disconnects user if he's connected. - /// \param barejid bare JID of user to unregister - /// \return false if there is no such user registered - bool unregisterUser(const std::string &barejid); - - /// Called when new user has been registered. - /// \param userInfo UserInfo struct with informations about user - boost::signal onUserRegistered; - - /// Called when user has been unregistered. - /// \param userInfo UserInfo struct with informations about user - boost::signal onUserUnregistered; - - /// Called when user's registration has been updated. - /// \param userInfo UserInfo struct with informations about user - boost::signal onUserUpdated; - - private: - virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); - virtual bool handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); - - void handleRegisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref error, const UserInfo &row); - void handleUnregisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref error, const std::string &barejid); - - Component *m_component; - StorageBackend *m_storageBackend; - UserManager *m_userManager; - Config *m_config; - -}; - -} +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * 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 02111-1301 USA + */ + +#pragma once + +#include "Swiften/Queries/Responder.h" +#include "Swiften/Elements/InBandRegistrationPayload.h" +#include "Swiften/Elements/RosterPayload.h" +#include +#include +#define HAVE_SWIFTEN_3 SWIFTEN_VERSION >= 0x030000 + +namespace Transport { + +struct UserInfo; +class Component; +class StorageBackend; +class UserManager; +class Config; + +/// Allows users to register the transport using service discovery. +class UserRegistration : public Swift::Responder { + public: + /// Creates new UserRegistration handler. + /// \param component Component associated with this class + /// \param userManager UserManager associated with this class + /// \param storageBackend StorageBackend where the registered users will be stored + UserRegistration(Component *component, UserManager *userManager, StorageBackend *storageBackend); + + /// Destroys UserRegistration. + ~UserRegistration(); + + /// Registers new user. This function stores user into database and subscribe user to transport. + /// \param userInfo UserInfo struct with informations about registered user + /// \return false if user is already registered + bool registerUser(const UserInfo &userInfo); + + /// Unregisters user. This function removes all data about user from databa, unsubscribe all buddies + /// managed by this transport and disconnects user if he's connected. + /// \param barejid bare JID of user to unregister + /// \return false if there is no such user registered + bool unregisterUser(const std::string &barejid); + + /// Called when new user has been registered. + /// \param userInfo UserInfo struct with informations about user + boost::signal onUserRegistered; + + /// Called when user has been unregistered. + /// \param userInfo UserInfo struct with informations about user + boost::signal onUserUnregistered; + + /// Called when user's registration has been updated. + /// \param userInfo UserInfo struct with informations about user + boost::signal onUserUpdated; + + private: + virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); + virtual bool handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); + + void handleRegisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref error, const UserInfo &row); + void handleUnregisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref error, const std::string &barejid); + + Component *m_component; + StorageBackend *m_storageBackend; + UserManager *m_userManager; + Config *m_config; + +}; + +} diff --git a/msvc-deps/CMakeLists.txt b/msvc-deps/CMakeLists.txt index b2130fc92c8faf547892e445286d6477e4e0bfb8..e830d462ab9664db3b301c0dc0d0aa4033a8a08b 100644 --- a/msvc-deps/CMakeLists.txt +++ b/msvc-deps/CMakeLists.txt @@ -1 +1 @@ -ADD_SUBDIRECTORY(sqlite3) +ADD_SUBDIRECTORY(sqlite3) diff --git a/msvc-deps/sqlite3/CMakeLists.txt b/msvc-deps/sqlite3/CMakeLists.txt index 7c940e54583e7d23009cdb43de73c430400431ac..87ae7fe3cdc3a40a4b7d8aafc9ad7a25808605f8 100644 --- a/msvc-deps/sqlite3/CMakeLists.txt +++ b/msvc-deps/sqlite3/CMakeLists.txt @@ -1,6 +1,6 @@ -cmake_minimum_required(VERSION 2.6) -FILE(GLOB SQLITE_SRC *.c *.h) - -ADD_LIBRARY(sqlite3 STATIC ${HEADERS} ${SQLITE_SRC}) - +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SQLITE_SRC *.c *.h) + +ADD_LIBRARY(sqlite3 STATIC ${HEADERS} ${SQLITE_SRC}) + INSTALL(TARGETS sqlite3 LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries) \ No newline at end of file diff --git a/plugin/cpp/CMakeLists.txt b/plugin/cpp/CMakeLists.txt index 75ea2aa156b5523670fc8c59824471e30a13e58c..4a15ba50b0e1607e051a216aa2e3eb8ae62ea167 100644 --- a/plugin/cpp/CMakeLists.txt +++ b/plugin/cpp/CMakeLists.txt @@ -1,38 +1,38 @@ -cmake_minimum_required(VERSION 2.6) -FILE(GLOB SRC *.cpp *.h) -FILE(GLOB HEADERS ../include/transport/*.h) - -set(EXTRA_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../src/memoryusage.cpp) -set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/logging.cpp) -set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/config.cpp) -set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/util.cpp) -set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) - -if (NOT WIN32) - ADD_LIBRARY(transport-plugin SHARED ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ${EXTRA_SOURCES}) -else() - ADD_LIBRARY(transport-plugin STATIC ${HEADERS} ${SRC} ${EXTRA_SOURCES} ) -endif() -ADD_DEPENDENCIES(transport-plugin pb) -SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) - -if (CMAKE_COMPILER_IS_GNUCXX) - if (NOT WIN32) - ADD_DEFINITIONS(-fPIC) - endif() -endif() - -if (NOT WIN32) - TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES}) -else() - TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ws2_32.lib) -endif() - -SET_TARGET_PROPERTIES(transport-plugin PROPERTIES - VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} -) - -INSTALL(TARGETS transport-plugin LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries) - -#CONFIGURE_FILE(transport.pc.in "${CMAKE_CURRENT_SOURCE_DIR}/transport.pc") -#INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/transport.pc" DESTINATION lib/pkgconfig) +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC *.cpp *.h) +FILE(GLOB HEADERS ../include/transport/*.h) + +set(EXTRA_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../src/memoryusage.cpp) +set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/logging.cpp) +set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/config.cpp) +set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/util.cpp) +set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) + +if (NOT WIN32) + ADD_LIBRARY(transport-plugin SHARED ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ${EXTRA_SOURCES}) +else() + ADD_LIBRARY(transport-plugin STATIC ${HEADERS} ${SRC} ${EXTRA_SOURCES} ) +endif() +ADD_DEPENDENCIES(transport-plugin pb) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) + +if (CMAKE_COMPILER_IS_GNUCXX) + if (NOT WIN32) + ADD_DEFINITIONS(-fPIC) + endif() +endif() + +if (NOT WIN32) + TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES}) +else() + TARGET_LINK_LIBRARIES(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ws2_32.lib) +endif() + +SET_TARGET_PROPERTIES(transport-plugin PROPERTIES + VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} +) + +INSTALL(TARGETS transport-plugin LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries) + +#CONFIGURE_FILE(transport.pc.in "${CMAKE_CURRENT_SOURCE_DIR}/transport.pc") +#INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/transport.pc" DESTINATION lib/pkgconfig) diff --git a/plugin/python/CMakeLists.txt b/plugin/python/CMakeLists.txt index 7b5fd03e3c9c3462f0d5d696353a8d6a5c5e86ac..6caa1a131b5d4a22da8bc4c6024a38424be64fbb 100644 --- a/plugin/python/CMakeLists.txt +++ b/plugin/python/CMakeLists.txt @@ -1,15 +1,15 @@ -cmake_minimum_required(VERSION 2.6) - -if (PROTOBUF_FOUND) - ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/protocol_pb2.py - COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --python_out ${CMAKE_CURRENT_SOURCE_DIR} --proto_path ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/ ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.proto - COMMENT "Running Python protocol buffer compiler on protocol.proto" - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.proto - ) - ADD_CUSTOM_TARGET(pb-python ALL DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol_pb2.py) -endif() - - - - +cmake_minimum_required(VERSION 2.6) + +if (PROTOBUF_FOUND) + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/protocol_pb2.py + COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --python_out ${CMAKE_CURRENT_SOURCE_DIR} --proto_path ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/ ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.proto + COMMENT "Running Python protocol buffer compiler on protocol.proto" + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.proto + ) + ADD_CUSTOM_TARGET(pb-python ALL DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol_pb2.py) +endif() + + + + diff --git a/spectrum/src/CMakeLists.txt b/spectrum/src/CMakeLists.txt index 005fbb32088fe3f756f3a5df6fec8ad86726f636..eb62ae98d8da96f8e6df4acb04331b3a24e1ba6c 100644 --- a/spectrum/src/CMakeLists.txt +++ b/spectrum/src/CMakeLists.txt @@ -1,48 +1,48 @@ -cmake_minimum_required(VERSION 2.6) -FILE(GLOB SRC *.cpp) - -if (WIN32) -FILE(GLOB WIN_SRC win32/*.cpp) -include_directories(win32) -include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3") -ADD_EXECUTABLE(spectrum2 ${SRC} ${WIN_SRC}) -else() -ADD_EXECUTABLE(spectrum2 ${SRC}) -endif() - - - -ADD_DEPENDENCIES(spectrum2 spectrum2_libpurple_backend) -ADD_DEPENDENCIES(spectrum2 spectrum2_libircclient-qt_backend) - -if (WIN32) -target_link_libraries(spectrum2 transport sqlite3 ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY}) -else () -target_link_libraries(spectrum2 transport ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY}) -endif() - -INSTALL(TARGETS spectrum2 RUNTIME DESTINATION bin) - -INSTALL(FILES - sample2_gateway.cfg - RENAME spectrum.cfg.example - DESTINATION /etc/spectrum2/transports - ) - -INSTALL(FILES - sample2.cfg - RENAME spectrum_server_mode.cfg.example - DESTINATION /etc/spectrum2/transports - ) - -INSTALL(FILES - backend-logging.cfg - DESTINATION /etc/spectrum2 - ) - -INSTALL(FILES - logging.cfg - DESTINATION /etc/spectrum2 - ) - - +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC *.cpp) + +if (WIN32) +FILE(GLOB WIN_SRC win32/*.cpp) +include_directories(win32) +include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3") +ADD_EXECUTABLE(spectrum2 ${SRC} ${WIN_SRC}) +else() +ADD_EXECUTABLE(spectrum2 ${SRC}) +endif() + + + +ADD_DEPENDENCIES(spectrum2 spectrum2_libpurple_backend) +ADD_DEPENDENCIES(spectrum2 spectrum2_libircclient-qt_backend) + +if (WIN32) +target_link_libraries(spectrum2 transport sqlite3 ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY}) +else () +target_link_libraries(spectrum2 transport ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY}) +endif() + +INSTALL(TARGETS spectrum2 RUNTIME DESTINATION bin) + +INSTALL(FILES + sample2_gateway.cfg + RENAME spectrum.cfg.example + DESTINATION /etc/spectrum2/transports + ) + +INSTALL(FILES + sample2.cfg + RENAME spectrum_server_mode.cfg.example + DESTINATION /etc/spectrum2/transports + ) + +INSTALL(FILES + backend-logging.cfg + DESTINATION /etc/spectrum2 + ) + +INSTALL(FILES + logging.cfg + DESTINATION /etc/spectrum2 + ) + + diff --git a/spectrum_manager/src/CMakeLists.txt b/spectrum_manager/src/CMakeLists.txt index 53b4e41e69564a4556bb63196368295470c6113f..ab00811efebb8f2c9134fa840417e5d2803595f0 100644 --- a/spectrum_manager/src/CMakeLists.txt +++ b/spectrum_manager/src/CMakeLists.txt @@ -1,19 +1,19 @@ -cmake_minimum_required(VERSION 2.6) -FILE(GLOB SRC *.cpp *.c) - -ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp ../../src/util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC *.cpp *.c) + +ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp ../../src/util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) ADD_DEPENDENCIES(spectrum2_manager pb) SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) -target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES}) +target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES}) if(APPLE) target_link_libraries(spectrum2_manager ${APPLE_FRAMEWORKS}) endif() -INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin) - -INSTALL(FILES - spectrum_manager.cfg - DESTINATION /etc/spectrum2 - ) +INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin) + +INSTALL(FILES + spectrum_manager.cfg + DESTINATION /etc/spectrum2 + ) diff --git a/spectrum_manager/src/main.cpp b/spectrum_manager/src/main.cpp index 58581be223f2d267103ff9547c910a46c37c00d3..3a267b0f380a7259133637984db5dfcadb528f28 100644 --- a/spectrum_manager/src/main.cpp +++ b/spectrum_manager/src/main.cpp @@ -1,200 +1,200 @@ -#include "managerconfig.h" -#include "methods.h" -#include "server.h" -#include "transport/config.h" -#include "transport/protocol.pb.h" -#include "Swiften/Swiften.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" - -#include -#include -#include -#include -#include -#include -#include -#include "signal.h" -#include "sys/wait.h" - - -using namespace Transport; - -using namespace boost::filesystem; - -using namespace boost; - - -// static void ask_local_servers(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &message) { -// path p(CONFIG_STRING(config, "service.config_directory")); -// -// try { -// if (!exists(p)) { -// std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; -// exit(6); -// } -// -// if (!is_directory(p)) { -// std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; -// exit(7); -// } -// -// directory_iterator end_itr; -// for (directory_iterator itr(p); itr != end_itr; ++itr) { -// if (is_regular(itr->path()) && extension(itr->path()) == ".cfg") { -// Config cfg; -// if (cfg.load(itr->path().string()) == false) { -// std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n"; -// continue; -// } -// -// if (CONFIG_VECTOR(&cfg, "service.admin_jid").empty() || CONFIG_STRING(&cfg, "service.admin_password").empty()) { -// std::cerr << itr->path().string() << ": service.admin_jid or service.admin_password empty. This server can't be queried over XMPP.\n"; -// continue; -// } -// -// finished++; -// Swift::Client *client = new Swift::Client(CONFIG_VECTOR(&cfg, "service.admin_jid")[0], CONFIG_STRING(&cfg, "service.admin_password"), &networkFactories); -// client->setAlwaysTrustCertificates(); -// client->onConnected.connect(boost::bind(&handleConnected, client, CONFIG_STRING(&cfg, "service.jid"))); -// client->onDisconnected.connect(bind(&handleDisconnected, client, _1, CONFIG_STRING(&cfg, "service.jid"))); -// client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1, CONFIG_STRING(&cfg, "service.jid"))); -// Swift::ClientOptions opt; -// opt.allowPLAINWithoutTLS = true; -// client->connect(opt); -// } -// } -// } -// catch (const filesystem_error& ex) { -// std::cerr << "boost filesystem error\n"; -// exit(5); -// } -// } - - -int main(int argc, char **argv) -{ - ManagerConfig config; - std::string config_file; - std::vector command; - boost::program_options::variables_map vm; - - boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \n" - " spectrum [OPTIONS] \nCommands:\n" - " start - start all local Spectrum2 instances\n" - " stop - stop all local Spectrum2 instances\n" - " restart - restart all local Spectrum2 instances\n" - " status - status of local Spectrum2 instances\n" - " - send command to local Spectrum2 instance and print output\n" - "Allowed options"); - desc.add_options() - ("help,h", "Show help output") - ("config,c", boost::program_options::value(&config_file)->default_value("/etc/spectrum2/spectrum_manager.cfg"), "Spectrum manager config file") - ("command", boost::program_options::value >(&command), "Command") - ; - try - { - boost::program_options::positional_options_description p; - p.add("command", -1); - boost::program_options::store(boost::program_options::command_line_parser(argc, argv). - options(desc).positional(p).run(), vm); - boost::program_options::notify(vm); - - if(vm.count("help")) - { - std::cout << desc << "\n"; - return 1; - } - } - catch (std::runtime_error& e) - { - std::cout << desc << "\n"; - return 2; - } - catch (...) - { - std::cout << desc << "\n"; - return 3; - } - - if (!config.load(config_file)) { - std::cerr << "Can't load configuration file.\n"; - return 4; - } - - if (command.empty()) { - std::cout << desc << "\n"; - return 1; - } - - if (command[0] == "start") { - return start_instances(&config); - } - else if (command[0] == "stop") { - stop_instances(&config); - } - else if (command[0] == "status") { - return show_status(&config); - } - else if (command[0] == "list") { - std::vector list = show_list(&config); - } - else if (command[0] == "restart") { - return restart_instances(&config); - } - else if (command[0] == "server") { - Server server(&config); - if (server.start() == false) { - std::cerr << "Can't set up server handler.\n"; - return 1; - } - while (1) { sleep(10); } - } - else { - if (command.size() < 2) { - std::cout << desc << "\n"; - return 11; - } - Swift::SimpleEventLoop eventLoop; - Swift::BoostNetworkFactories networkFactories(&eventLoop); - - std::string jid = command[0]; - command.erase(command.begin()); - std::string cmd = boost::algorithm::join(command, " "); - - if (cmd == "start") { - return start_instances(&config, jid); - } - else if (cmd == "stop") { - stop_instances(&config, jid); - return 0; - } - else if (cmd == "restart") { - return restart_instances(&config, jid); - } - - ask_local_server(&config, networkFactories, jid, cmd); -// std::string message = command; -// m = &message; - -// ask_local_server(&config, networkFactories, message); - - eventLoop.runUntilEvents(); - - - struct timeval td_start,td_end; - float elapsed = 0; - gettimeofday(&td_start, NULL); - - time_t started = time(NULL); - while(get_response().empty()) { - eventLoop.runUntilEvents(); - } - if (!get_response().empty()) { - gettimeofday(&td_end, NULL); - elapsed = 1000000.0 * (td_end.tv_sec -td_start.tv_sec); \ - elapsed += (td_end.tv_usec - td_start.tv_usec); \ - elapsed = elapsed / 1000 / 1000; \ -// std::cout << "Response received after " << (elapsed) << " seconds\n"; - } - } -} +#include "managerconfig.h" +#include "methods.h" +#include "server.h" +#include "transport/config.h" +#include "transport/protocol.pb.h" +#include "Swiften/Swiften.h" +#include "Swiften/EventLoop/SimpleEventLoop.h" + +#include +#include +#include +#include +#include +#include +#include +#include "signal.h" +#include "sys/wait.h" + + +using namespace Transport; + +using namespace boost::filesystem; + +using namespace boost; + + +// static void ask_local_servers(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &message) { +// path p(CONFIG_STRING(config, "service.config_directory")); +// +// try { +// if (!exists(p)) { +// std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; +// exit(6); +// } +// +// if (!is_directory(p)) { +// std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; +// exit(7); +// } +// +// directory_iterator end_itr; +// for (directory_iterator itr(p); itr != end_itr; ++itr) { +// if (is_regular(itr->path()) && extension(itr->path()) == ".cfg") { +// Config cfg; +// if (cfg.load(itr->path().string()) == false) { +// std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n"; +// continue; +// } +// +// if (CONFIG_VECTOR(&cfg, "service.admin_jid").empty() || CONFIG_STRING(&cfg, "service.admin_password").empty()) { +// std::cerr << itr->path().string() << ": service.admin_jid or service.admin_password empty. This server can't be queried over XMPP.\n"; +// continue; +// } +// +// finished++; +// Swift::Client *client = new Swift::Client(CONFIG_VECTOR(&cfg, "service.admin_jid")[0], CONFIG_STRING(&cfg, "service.admin_password"), &networkFactories); +// client->setAlwaysTrustCertificates(); +// client->onConnected.connect(boost::bind(&handleConnected, client, CONFIG_STRING(&cfg, "service.jid"))); +// client->onDisconnected.connect(bind(&handleDisconnected, client, _1, CONFIG_STRING(&cfg, "service.jid"))); +// client->onMessageReceived.connect(bind(&handleMessageReceived, client, _1, CONFIG_STRING(&cfg, "service.jid"))); +// Swift::ClientOptions opt; +// opt.allowPLAINWithoutTLS = true; +// client->connect(opt); +// } +// } +// } +// catch (const filesystem_error& ex) { +// std::cerr << "boost filesystem error\n"; +// exit(5); +// } +// } + + +int main(int argc, char **argv) +{ + ManagerConfig config; + std::string config_file; + std::vector command; + boost::program_options::variables_map vm; + + boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \n" + " spectrum [OPTIONS] \nCommands:\n" + " start - start all local Spectrum2 instances\n" + " stop - stop all local Spectrum2 instances\n" + " restart - restart all local Spectrum2 instances\n" + " status - status of local Spectrum2 instances\n" + " - send command to local Spectrum2 instance and print output\n" + "Allowed options"); + desc.add_options() + ("help,h", "Show help output") + ("config,c", boost::program_options::value(&config_file)->default_value("/etc/spectrum2/spectrum_manager.cfg"), "Spectrum manager config file") + ("command", boost::program_options::value >(&command), "Command") + ; + try + { + boost::program_options::positional_options_description p; + p.add("command", -1); + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(desc).positional(p).run(), vm); + boost::program_options::notify(vm); + + if(vm.count("help")) + { + std::cout << desc << "\n"; + return 1; + } + } + catch (std::runtime_error& e) + { + std::cout << desc << "\n"; + return 2; + } + catch (...) + { + std::cout << desc << "\n"; + return 3; + } + + if (!config.load(config_file)) { + std::cerr << "Can't load configuration file.\n"; + return 4; + } + + if (command.empty()) { + std::cout << desc << "\n"; + return 1; + } + + if (command[0] == "start") { + return start_instances(&config); + } + else if (command[0] == "stop") { + stop_instances(&config); + } + else if (command[0] == "status") { + return show_status(&config); + } + else if (command[0] == "list") { + std::vector list = show_list(&config); + } + else if (command[0] == "restart") { + return restart_instances(&config); + } + else if (command[0] == "server") { + Server server(&config); + if (server.start() == false) { + std::cerr << "Can't set up server handler.\n"; + return 1; + } + while (1) { sleep(10); } + } + else { + if (command.size() < 2) { + std::cout << desc << "\n"; + return 11; + } + Swift::SimpleEventLoop eventLoop; + Swift::BoostNetworkFactories networkFactories(&eventLoop); + + std::string jid = command[0]; + command.erase(command.begin()); + std::string cmd = boost::algorithm::join(command, " "); + + if (cmd == "start") { + return start_instances(&config, jid); + } + else if (cmd == "stop") { + stop_instances(&config, jid); + return 0; + } + else if (cmd == "restart") { + return restart_instances(&config, jid); + } + + ask_local_server(&config, networkFactories, jid, cmd); +// std::string message = command; +// m = &message; + +// ask_local_server(&config, networkFactories, message); + + eventLoop.runUntilEvents(); + + + struct timeval td_start,td_end; + float elapsed = 0; + gettimeofday(&td_start, NULL); + + time_t started = time(NULL); + while(get_response().empty()) { + eventLoop.runUntilEvents(); + } + if (!get_response().empty()) { + gettimeofday(&td_end, NULL); + elapsed = 1000000.0 * (td_end.tv_sec -td_start.tv_sec); \ + elapsed += (td_end.tv_usec - td_start.tv_usec); \ + elapsed = elapsed / 1000 / 1000; \ +// std::cout << "Response received after " << (elapsed) << " seconds\n"; + } + } +} diff --git a/spectrum_manager/src/mongoose.c b/spectrum_manager/src/mongoose.c index 8d52417b0b4b30db737f5ec70cfafef4706672e0..8881ecb6dc82b2a4dbc4eaca2461984aeb22990a 100644 --- a/spectrum_manager/src/mongoose.c +++ b/spectrum_manager/src/mongoose.c @@ -1,4472 +1,4472 @@ -// Copyright (c) 2004-2012 Sergey Lyubka -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include - -#if defined(_WIN32) -#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005 -#else -#define _XOPEN_SOURCE 600 // For flockfile() on Linux -#define _LARGEFILE_SOURCE // Enable 64-bit file offsets -#define __STDC_FORMAT_MACROS // wants this for C++ -#define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX -#endif - -#if defined(__SYMBIAN32__) -#define NO_SSL // SSL is not supported -#define NO_CGI // CGI is not supported -#define PATH_MAX FILENAME_MAX -#endif // __SYMBIAN32__ - -#ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE -#include -#include -#include -#include -#include -#endif // !_WIN32_WCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific -#define _WIN32_WINNT 0x0400 // To make it link in VS2005 -#include - -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif - -#ifndef _WIN32_WCE -#include -#include -#include -#else // _WIN32_WCE -#include -#include -#define NO_CGI // WinCE has no pipes - -typedef long off_t; - -#define errno GetLastError() -#define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10) -#endif // _WIN32_WCE - -#define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \ - ((uint64_t)((uint32_t)(hi))) << 32)) -#define RATE_DIFF 10000000 // 100 nsecs -#define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de) -#define SYS2UNIX_TIME(lo, hi) \ - (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF) - -// Visual Studio 6 does not know __func__ or __FUNCTION__ -// The rest of MS compilers use __FUNCTION__, not C99 __func__ -// Also use _strtoui64 on modern M$ compilers -#if defined(_MSC_VER) && _MSC_VER < 1300 -#define STRX(x) #x -#define STR(x) STRX(x) -#define __func__ "line " STR(__LINE__) -#define strtoull(x, y, z) strtoul(x, y, z) -#define strtoll(x, y, z) strtol(x, y, z) -#else -#define __func__ __FUNCTION__ -#define strtoull(x, y, z) _strtoui64(x, y, z) -#define strtoll(x, y, z) _strtoi64(x, y, z) -#endif // _MSC_VER - -#define ERRNO GetLastError() -#define NO_SOCKLEN_T -#define SSL_LIB "ssleay32.dll" -#define CRYPTO_LIB "libeay32.dll" -#define DIRSEP '\\' -#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\') -#define O_NONBLOCK 0 -#if !defined(EWOULDBLOCK) -#define EWOULDBLOCK WSAEWOULDBLOCK -#endif // !EWOULDBLOCK -#define _POSIX_ -#define INT64_FMT "I64d" - -#define WINCDECL __cdecl -#define SHUT_WR 1 -#define snprintf _snprintf -#define vsnprintf _vsnprintf -#define mg_sleep(x) Sleep(x) - -#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY) -#define popen(x, y) _popen(x, y) -#define pclose(x) _pclose(x) -#define close(x) _close(x) -#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y)) -#define RTLD_LAZY 0 -#define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z)) -#define fdopen(x, y) _fdopen((x), (y)) -#define write(x, y, z) _write((x), (y), (unsigned) z) -#define read(x, y, z) _read((x), (y), (unsigned) z) -#define flockfile(x) EnterCriticalSection(&global_log_file_lock) -#define funlockfile(x) LeaveCriticalSection(&global_log_file_lock) - -#if !defined(fileno) -#define fileno(x) _fileno(x) -#endif // !fileno MINGW #defines fileno - -typedef HANDLE pthread_mutex_t; -typedef struct {HANDLE signal, broadcast;} pthread_cond_t; -typedef DWORD pthread_t; -#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here. - -struct timespec { - long tv_nsec; - long tv_sec; -}; - -static int pthread_mutex_lock(pthread_mutex_t *); -static int pthread_mutex_unlock(pthread_mutex_t *); -static FILE *mg_fopen(const char *path, const char *mode); - -#if defined(HAVE_STDINT) -#include -#else -typedef unsigned int uint32_t; -typedef unsigned short uint16_t; -typedef unsigned __int64 uint64_t; -typedef __int64 int64_t; -#define INT64_MAX 9223372036854775807 -#endif // HAVE_STDINT - -// POSIX dirent interface -struct dirent { - char d_name[PATH_MAX]; -}; - -typedef struct DIR { - HANDLE handle; - WIN32_FIND_DATAW info; - struct dirent result; -} DIR; - -#else // UNIX specific -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#if !defined(NO_SSL_DL) && !defined(NO_SSL) -#include -#endif -#include -#if defined(__MACH__) -#define SSL_LIB "libssl.dylib" -#define CRYPTO_LIB "libcrypto.dylib" -#else -#if !defined(SSL_LIB) -#define SSL_LIB "libssl.so" -#endif -#if !defined(CRYPTO_LIB) -#define CRYPTO_LIB "libcrypto.so" -#endif -#endif -#define DIRSEP '/' -#define IS_DIRSEP_CHAR(c) ((c) == '/') -#ifndef O_BINARY -#define O_BINARY 0 -#endif // O_BINARY -#define closesocket(a) close(a) -#define mg_fopen(x, y) fopen(x, y) -#define mg_mkdir(x, y) mkdir(x, y) -#define mg_remove(x) remove(x) -#define mg_rename(x, y) rename(x, y) -#define mg_sleep(x) usleep((x) * 1000) -#define ERRNO errno -#define INVALID_SOCKET (-1) -#define INT64_FMT PRId64 -typedef int SOCKET; -#define WINCDECL - -#endif // End of Windows and UNIX specific includes - -#include "mongoose.h" - -#define MONGOOSE_VERSION "3.3" -#define PASSWORDS_FILE_NAME ".htpasswd" -#define CGI_ENVIRONMENT_SIZE 4096 -#define MAX_CGI_ENVIR_VARS 64 -#define MG_BUF_LEN 8192 -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) - -#ifdef _WIN32 -static CRITICAL_SECTION global_log_file_lock; -static pthread_t pthread_self(void) { - return GetCurrentThreadId(); -} -#endif // _WIN32 - -#if defined(DEBUG) -#define DEBUG_TRACE(x) do { \ - flockfile(stdout); \ - printf("*** %lu.%p.%s.%d: ", \ - (unsigned long) time(NULL), (void *) pthread_self(), \ - __func__, __LINE__); \ - printf x; \ - putchar('\n'); \ - fflush(stdout); \ - funlockfile(stdout); \ -} while (0) -#else -#define DEBUG_TRACE(x) -#endif // DEBUG - -// Darwin prior to 7.0 and Win32 do not have socklen_t -#ifdef NO_SOCKLEN_T -typedef int socklen_t; -#endif // NO_SOCKLEN_T -#define _DARWIN_UNLIMITED_SELECT - -#if !defined(MSG_NOSIGNAL) -#define MSG_NOSIGNAL 0 -#endif - -#if !defined(SOMAXCONN) -#define SOMAXCONN 100 -#endif - -static const char *http_500_error = "Internal Server Error"; - -// Snatched from OpenSSL includes. I put the prototypes here to be independent -// from the OpenSSL source installation. Having this, mongoose + SSL can be -// built on any system with binary SSL libraries installed. -typedef struct ssl_st SSL; -typedef struct ssl_method_st SSL_METHOD; -typedef struct ssl_ctx_st SSL_CTX; - -#define SSL_ERROR_WANT_READ 2 -#define SSL_ERROR_WANT_WRITE 3 -#define SSL_FILETYPE_PEM 1 -#define CRYPTO_LOCK 1 - -#if defined(NO_SSL_DL) -extern void SSL_free(SSL *); -extern int SSL_accept(SSL *); -extern int SSL_connect(SSL *); -extern int SSL_read(SSL *, void *, int); -extern int SSL_write(SSL *, const void *, int); -extern int SSL_get_error(const SSL *, int); -extern int SSL_set_fd(SSL *, int); -extern SSL *SSL_new(SSL_CTX *); -extern SSL_CTX *SSL_CTX_new(SSL_METHOD *); -extern SSL_METHOD *SSLv23_server_method(void); -extern SSL_METHOD *SSLv23_client_method(void); -extern int SSL_library_init(void); -extern void SSL_load_error_strings(void); -extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int); -extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int); -extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *); -extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t); -extern void SSL_CTX_free(SSL_CTX *); -extern unsigned long ERR_get_error(void); -extern char *ERR_error_string(unsigned long, char *); -extern int CRYPTO_num_locks(void); -extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int)); -extern void CRYPTO_set_id_callback(unsigned long (*)(void)); -#else -// Dynamically loaded SSL functionality -struct ssl_func { - const char *name; // SSL function name - void (*ptr)(void); // Function pointer -}; - -#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr) -#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr) -#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr) -#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr) -#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr) -#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr) -#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr) -#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr) -#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr) -#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr) -#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr) -#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \ - const char *, int)) ssl_sw[11].ptr) -#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \ - const char *, int)) ssl_sw[12].ptr) -#define SSL_CTX_set_default_passwd_cb \ - (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr) -#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr) -#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr) -#define SSL_CTX_use_certificate_chain_file \ - (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr) -#define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr) - -#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr) -#define CRYPTO_set_locking_callback \ - (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr) -#define CRYPTO_set_id_callback \ - (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr) -#define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr) -#define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr) - -// set_ssl_option() function updates this array. -// It loads SSL library dynamically and changes NULLs to the actual addresses -// of respective functions. The macros above (like SSL_connect()) are really -// just calling these functions indirectly via the pointer. -static struct ssl_func ssl_sw[] = { - {"SSL_free", NULL}, - {"SSL_accept", NULL}, - {"SSL_connect", NULL}, - {"SSL_read", NULL}, - {"SSL_write", NULL}, - {"SSL_get_error", NULL}, - {"SSL_set_fd", NULL}, - {"SSL_new", NULL}, - {"SSL_CTX_new", NULL}, - {"SSLv23_server_method", NULL}, - {"SSL_library_init", NULL}, - {"SSL_CTX_use_PrivateKey_file", NULL}, - {"SSL_CTX_use_certificate_file",NULL}, - {"SSL_CTX_set_default_passwd_cb",NULL}, - {"SSL_CTX_free", NULL}, - {"SSL_load_error_strings", NULL}, - {"SSL_CTX_use_certificate_chain_file", NULL}, - {"SSLv23_client_method", NULL}, - {NULL, NULL} -}; - -// Similar array as ssl_sw. These functions could be located in different lib. -#if !defined(NO_SSL) -static struct ssl_func crypto_sw[] = { - {"CRYPTO_num_locks", NULL}, - {"CRYPTO_set_locking_callback", NULL}, - {"CRYPTO_set_id_callback", NULL}, - {"ERR_get_error", NULL}, - {"ERR_error_string", NULL}, - {NULL, NULL} -}; -#endif // NO_SSL -#endif // NO_SSL_DL - -static const char *month_names[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -// Unified socket address. For IPv6 support, add IPv6 address structure -// in the union u. -union usa { - struct sockaddr sa; - struct sockaddr_in sin; -#if defined(USE_IPV6) - struct sockaddr_in6 sin6; -#endif -}; - -// Describes a string (chunk of memory). -struct vec { - const char *ptr; - size_t len; -}; - -// Structure used by mg_stat() function. Uses 64 bit file length. -struct mgstat { - int is_directory; // Directory marker - int64_t size; // File size - time_t mtime; // Modification time -}; - -// Describes listening socket, or socket which was accept()-ed by the master -// thread and queued for future handling by the worker thread. -struct socket { - struct socket *next; // Linkage - SOCKET sock; // Listening socket - union usa lsa; // Local socket address - union usa rsa; // Remote socket address - int is_ssl; // Is socket SSL-ed -}; - -// NOTE(lsm): this enum shoulds be in sync with the config_options below. -enum { - CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER, - MAX_REQUEST_SIZE, PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, - ACCESS_LOG_FILE, SSL_CHAIN_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE, - GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, - EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE, - NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, - NUM_OPTIONS -}; - -static const char *config_options[] = { - "C", "cgi_pattern", "**.cgi$|**.pl$|**.php$", - "E", "cgi_environment", NULL, - "G", "put_delete_passwords_file", NULL, - "I", "cgi_interpreter", NULL, - "M", "max_request_size", "16384", - "P", "protect_uri", NULL, - "R", "authentication_domain", "mydomain.com", - "S", "ssi_pattern", "**.shtml$|**.shtm$", - "a", "access_log_file", NULL, - "c", "ssl_chain_file", NULL, - "d", "enable_directory_listing", "yes", - "e", "error_log_file", NULL, - "g", "global_passwords_file", NULL, - "i", "index_files", "index.html,index.htm,index.cgi,index.shtml,index.php", - "k", "enable_keep_alive", "no", - "l", "access_control_list", NULL, - "m", "extra_mime_types", NULL, - "p", "listening_ports", "8080", - "r", "document_root", ".", - "s", "ssl_certificate", NULL, - "t", "num_threads", "10", - "u", "run_as_user", NULL, - "w", "url_rewrite_patterns", NULL, - "x", "hide_files_patterns", NULL, - NULL -}; -#define ENTRIES_PER_CONFIG_OPTION 3 - -struct mg_context { - volatile int stop_flag; // Should we stop event loop - SSL_CTX *ssl_ctx; // SSL context - SSL_CTX *client_ssl_ctx; // Client SSL context - char *config[NUM_OPTIONS]; // Mongoose configuration parameters - mg_callback_t user_callback; // User-defined callback function - void *user_data; // User-defined data - - struct socket *listening_sockets; - - volatile int num_threads; // Number of threads - pthread_mutex_t mutex; // Protects (max|num)_threads - pthread_cond_t cond; // Condvar for tracking workers terminations - - struct socket queue[20]; // Accepted sockets - volatile int sq_head; // Head of the socket queue - volatile int sq_tail; // Tail of the socket queue - pthread_cond_t sq_full; // Signaled when socket is produced - pthread_cond_t sq_empty; // Signaled when socket is consumed -}; - -struct mg_connection { - struct mg_request_info request_info; - struct mg_context *ctx; - SSL *ssl; // SSL descriptor - struct socket client; // Connected client - time_t birth_time; // Time when request was received - int64_t num_bytes_sent; // Total bytes sent to client - int64_t content_len; // Content-Length header value - int64_t consumed_content; // How many bytes of content have been read - char *buf; // Buffer for received data - char *path_info; // PATH_INFO part of the URL - char *body; // Pointer to not-read yet buffered body data - char *next_request; // Pointer to the buffered next request - int must_close; // 1 if connection must be closed - int buf_size; // Buffer size - int request_len; // Size of the request + headers in a buffer - int data_len; // Total size of data in a buffer -}; - -const char **mg_get_valid_option_names(void) { - return config_options; -} - -static void *call_user(struct mg_connection *conn, enum mg_event event) { - conn->request_info.user_data = conn->ctx->user_data; - return conn->ctx->user_callback == NULL ? NULL : - conn->ctx->user_callback(event, conn); -} - -static int get_option_index(const char *name) { - int i; - - for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) { - if (strcmp(config_options[i], name) == 0 || - strcmp(config_options[i + 1], name) == 0) { - return i / ENTRIES_PER_CONFIG_OPTION; - } - } - return -1; -} - -const char *mg_get_option(const struct mg_context *ctx, const char *name) { - int i; - if ((i = get_option_index(name)) == -1) { - return NULL; - } else if (ctx->config[i] == NULL) { - return ""; - } else { - return ctx->config[i]; - } -} - -static void sockaddr_to_string(char *buf, size_t len, - const union usa *usa) { - buf[0] = '\0'; -#if defined(USE_IPV6) - inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ? - (void *) &usa->sin.sin_addr : - (void *) &usa->sin6.sin6_addr, buf, len); -#elif defined(_WIN32) - // Only Windoze Vista (and newer) have inet_ntop() - strncpy(buf, inet_ntoa(usa->sin.sin_addr), len); -#else - inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len); -#endif -} - -// Print error message to the opened error log stream. -static void cry(struct mg_connection *conn, const char *fmt, ...) { - char buf[MG_BUF_LEN], src_addr[20]; - va_list ap; - FILE *fp; - time_t timestamp; - - va_start(ap, fmt); - (void) vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - // Do not lock when getting the callback value, here and below. - // I suppose this is fine, since function cannot disappear in the - // same way string option can. - conn->request_info.log_message = buf; - if (call_user(conn, MG_EVENT_LOG) == NULL) { - fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL : - mg_fopen(conn->ctx->config[ERROR_LOG_FILE], "a+"); - - if (fp != NULL) { - flockfile(fp); - timestamp = time(NULL); - - sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa); - fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp, - src_addr); - - if (conn->request_info.request_method != NULL) { - fprintf(fp, "%s %s: ", conn->request_info.request_method, - conn->request_info.uri); - } - - (void) fprintf(fp, "%s", buf); - fputc('\n', fp); - funlockfile(fp); - if (fp != stderr) { - fclose(fp); - } - } - } - conn->request_info.log_message = NULL; -} - -// Return fake connection structure. Used for logging, if connection -// is not applicable at the moment of logging. -static struct mg_connection *fc(struct mg_context *ctx) { - static struct mg_connection fake_connection; - fake_connection.ctx = ctx; - return &fake_connection; -} - -const char *mg_version(void) { - return MONGOOSE_VERSION; -} - -const struct mg_request_info * -mg_get_request_info(const struct mg_connection *conn) { - return &conn->request_info; -} - -static void mg_strlcpy(register char *dst, register const char *src, size_t n) { - for (; *src != '\0' && n > 1; n--) { - *dst++ = *src++; - } - *dst = '\0'; -} - -static int lowercase(const char *s) { - return tolower(* (const unsigned char *) s); -} - -static int mg_strncasecmp(const char *s1, const char *s2, size_t len) { - int diff = 0; - - if (len > 0) - do { - diff = lowercase(s1++) - lowercase(s2++); - } while (diff == 0 && s1[-1] != '\0' && --len > 0); - - return diff; -} - -static int mg_strcasecmp(const char *s1, const char *s2) { - int diff; - - do { - diff = lowercase(s1++) - lowercase(s2++); - } while (diff == 0 && s1[-1] != '\0'); - - return diff; -} - -static char * mg_strndup(const char *ptr, size_t len) { - char *p; - - if ((p = (char *) malloc(len + 1)) != NULL) { - mg_strlcpy(p, ptr, len + 1); - } - - return p; -} - -static char * mg_strdup(const char *str) { - return mg_strndup(str, strlen(str)); -} - -// Like snprintf(), but never returns negative value, or a value -// that is larger than a supplied buffer. -// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability -// in his audit report. -static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen, - const char *fmt, va_list ap) { - int n; - - if (buflen == 0) - return 0; - - n = vsnprintf(buf, buflen, fmt, ap); - - if (n < 0) { - cry(conn, "vsnprintf error"); - n = 0; - } else if (n >= (int) buflen) { - cry(conn, "truncating vsnprintf buffer: [%.*s]", - n > 200 ? 200 : n, buf); - n = (int) buflen - 1; - } - buf[n] = '\0'; - - return n; -} - -static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, - const char *fmt, ...) { - va_list ap; - int n; - - va_start(ap, fmt); - n = mg_vsnprintf(conn, buf, buflen, fmt, ap); - va_end(ap); - - return n; -} - -// Skip the characters until one of the delimiters characters found. -// 0-terminate resulting word. Skip the delimiter and following whitespaces if any. -// Advance pointer to buffer to the next word. Return found 0-terminated word. -// Delimiters can be quoted with quotechar. -static char *skip_quoted(char **buf, const char *delimiters, - const char *whitespace, char quotechar) { - char *p, *begin_word, *end_word, *end_whitespace; - - begin_word = *buf; - end_word = begin_word + strcspn(begin_word, delimiters); - - // Check for quotechar - if (end_word > begin_word) { - p = end_word - 1; - while (*p == quotechar) { - // If there is anything beyond end_word, copy it - if (*end_word == '\0') { - *p = '\0'; - break; - } else { - size_t end_off = strcspn(end_word + 1, delimiters); - memmove (p, end_word, end_off + 1); - p += end_off; // p must correspond to end_word - 1 - end_word += end_off + 1; - } - } - for (p++; p < end_word; p++) { - *p = '\0'; - } - } - - if (*end_word == '\0') { - *buf = end_word; - } else { - end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace); - - for (p = end_word; p < end_whitespace; p++) { - *p = '\0'; - } - - *buf = end_whitespace; - } - - return begin_word; -} - -// Simplified version of skip_quoted without quote char -// and whitespace == delimiters -static char *skip(char **buf, const char *delimiters) { - return skip_quoted(buf, delimiters, delimiters, 0); -} - - -// Return HTTP header value, or NULL if not found. -static const char *get_header(const struct mg_request_info *ri, - const char *name) { - int i; - - for (i = 0; i < ri->num_headers; i++) - if (!mg_strcasecmp(name, ri->http_headers[i].name)) - return ri->http_headers[i].value; - - return NULL; -} - -const char *mg_get_header(const struct mg_connection *conn, const char *name) { - return get_header(&conn->request_info, name); -} - -// A helper function for traversing a comma separated list of values. -// It returns a list pointer shifted to the next value, or NULL if the end -// of the list found. -// Value is stored in val vector. If value has form "x=y", then eq_val -// vector is initialized to point to the "y" part, and val vector length -// is adjusted to point only to "x". -static const char *next_option(const char *list, struct vec *val, - struct vec *eq_val) { - if (list == NULL || *list == '\0') { - // End of the list - list = NULL; - } else { - val->ptr = list; - if ((list = strchr(val->ptr, ',')) != NULL) { - // Comma found. Store length and shift the list ptr - val->len = list - val->ptr; - list++; - } else { - // This value is the last one - list = val->ptr + strlen(val->ptr); - val->len = list - val->ptr; - } - - if (eq_val != NULL) { - // Value has form "x=y", adjust pointers and lengths - // so that val points to "x", and eq_val points to "y". - eq_val->len = 0; - eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len); - if (eq_val->ptr != NULL) { - eq_val->ptr++; // Skip over '=' character - eq_val->len = val->ptr + val->len - eq_val->ptr; - val->len = (eq_val->ptr - val->ptr) - 1; - } - } - } - - return list; -} - -static int match_prefix(const char *pattern, int pattern_len, const char *str) { - const char *or_str; - int i, j, len, res; - - if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) { - res = match_prefix(pattern, or_str - pattern, str); - return res > 0 ? res : - match_prefix(or_str + 1, (pattern + pattern_len) - (or_str + 1), str); - } - - i = j = 0; - res = -1; - for (; i < pattern_len; i++, j++) { - if (pattern[i] == '?' && str[j] != '\0') { - continue; - } else if (pattern[i] == '$') { - return str[j] == '\0' ? j : -1; - } else if (pattern[i] == '*') { - i++; - if (pattern[i] == '*') { - i++; - len = (int) strlen(str + j); - } else { - len = (int) strcspn(str + j, "/"); - } - if (i == pattern_len) { - return j + len; - } - do { - res = match_prefix(pattern + i, pattern_len - i, str + j + len); - } while (res == -1 && len-- > 0); - return res == -1 ? -1 : j + res + len; - } else if (pattern[i] != str[j]) { - return -1; - } - } - return j; -} - -// HTTP 1.1 assumes keep alive if "Connection:" header is not set -// This function must tolerate situations when connection info is not -// set up, for example if request parsing failed. -static int should_keep_alive(const struct mg_connection *conn) { - const char *http_version = conn->request_info.http_version; - const char *header = mg_get_header(conn, "Connection"); - if (conn->must_close || - conn->request_info.status_code == 401 || - mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 || - (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) || - (header == NULL && http_version && strcmp(http_version, "1.1"))) { - return 0; - } - return 1; -} - -static const char *suggest_connection_header(const struct mg_connection *conn) { - return should_keep_alive(conn) ? "keep-alive" : "close"; -} - -static void send_http_error(struct mg_connection *, int, const char *, - PRINTF_FORMAT_STRING(const char *fmt), ...) - PRINTF_ARGS(4, 5); - - -static void send_http_error(struct mg_connection *conn, int status, - const char *reason, const char *fmt, ...) { - char buf[MG_BUF_LEN]; - va_list ap; - int len; - - conn->request_info.status_code = status; - - if (call_user(conn, MG_HTTP_ERROR) == NULL) { - buf[0] = '\0'; - len = 0; - - // Errors 1xx, 204 and 304 MUST NOT send a body - if (status > 199 && status != 204 && status != 304) { - len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason); - buf[len++] = '\n'; - - va_start(ap, fmt); - len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap); - va_end(ap); - } - DEBUG_TRACE(("[%s]", buf)); - - mg_printf(conn, "HTTP/1.1 %d %s\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: %d\r\n" - "Connection: %s\r\n\r\n", status, reason, len, - suggest_connection_header(conn)); - conn->num_bytes_sent += mg_printf(conn, "%s", buf); - } -} - -#if defined(_WIN32) && !defined(__SYMBIAN32__) -static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) { - unused = NULL; - *mutex = CreateMutex(NULL, FALSE, NULL); - return *mutex == NULL ? -1 : 0; -} - -static int pthread_mutex_destroy(pthread_mutex_t *mutex) { - return CloseHandle(*mutex) == 0 ? -1 : 0; -} - -static int pthread_mutex_lock(pthread_mutex_t *mutex) { - return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1; -} - -static int pthread_mutex_unlock(pthread_mutex_t *mutex) { - return ReleaseMutex(*mutex) == 0 ? -1 : 0; -} - -static int pthread_cond_init(pthread_cond_t *cv, const void *unused) { - unused = NULL; - cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL); - cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL); - return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1; -} - -static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) { - HANDLE handles[] = {cv->signal, cv->broadcast}; - ReleaseMutex(*mutex); - WaitForMultipleObjects(2, handles, FALSE, INFINITE); - return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1; -} - -static int pthread_cond_signal(pthread_cond_t *cv) { - return SetEvent(cv->signal) == 0 ? -1 : 0; -} - -static int pthread_cond_broadcast(pthread_cond_t *cv) { - // Implementation with PulseEvent() has race condition, see - // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - return PulseEvent(cv->broadcast) == 0 ? -1 : 0; -} - -static int pthread_cond_destroy(pthread_cond_t *cv) { - return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1; -} - -// For Windows, change all slashes to backslashes in path names. -static void change_slashes_to_backslashes(char *path) { - int i; - - for (i = 0; path[i] != '\0'; i++) { - if (path[i] == '/') - path[i] = '\\'; - // i > 0 check is to preserve UNC paths, like \\server\file.txt - if (path[i] == '\\' && i > 0) - while (path[i + 1] == '\\' || path[i + 1] == '/') - (void) memmove(path + i + 1, - path + i + 2, strlen(path + i + 1)); - } -} - -// Encode 'path' which is assumed UTF-8 string, into UNICODE string. -// wbuf and wbuf_len is a target buffer and its length. -static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) { - char buf[PATH_MAX], buf2[PATH_MAX], *p; - - mg_strlcpy(buf, path, sizeof(buf)); - change_slashes_to_backslashes(buf); - - // Point p to the end of the file name - p = buf + strlen(buf) - 1; - - // Trim trailing backslash character - while (p > buf && *p == '\\' && p[-1] != ':') { - *p-- = '\0'; - } - - // Protect from CGI code disclosure. - // This is very nasty hole. Windows happily opens files with - // some garbage in the end of file name. So fopen("a.cgi ", "r") - // actually opens "a.cgi", and does not return an error! - if (*p == 0x20 || // No space at the end - (*p == 0x2e && p > buf) || // No '.' but allow '.' as full path - *p == 0x2b || // No '+' - (*p & ~0x7f)) { // And generally no non-ASCII chars - (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf); - wbuf[0] = L'\0'; - } else { - // Convert to Unicode and back. If doubly-converted string does not - // match the original, something is fishy, reject. - memset(wbuf, 0, wbuf_len * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); - WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), - NULL, NULL); - if (strcmp(buf, buf2) != 0) { - wbuf[0] = L'\0'; - } - } -} - -#if defined(_WIN32_WCE) -static time_t time(time_t *ptime) { - time_t t; - SYSTEMTIME st; - FILETIME ft; - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &ft); - t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime); - - if (ptime != NULL) { - *ptime = t; - } - - return t; -} - -static struct tm *localtime(const time_t *ptime, struct tm *ptm) { - int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF; - FILETIME ft, lft; - SYSTEMTIME st; - TIME_ZONE_INFORMATION tzinfo; - - if (ptm == NULL) { - return NULL; - } - - * (int64_t *) &ft = t; - FileTimeToLocalFileTime(&ft, &lft); - FileTimeToSystemTime(&lft, &st); - ptm->tm_year = st.wYear - 1900; - ptm->tm_mon = st.wMonth - 1; - ptm->tm_wday = st.wDayOfWeek; - ptm->tm_mday = st.wDay; - ptm->tm_hour = st.wHour; - ptm->tm_min = st.wMinute; - ptm->tm_sec = st.wSecond; - ptm->tm_yday = 0; // hope nobody uses this - ptm->tm_isdst = - GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0; - - return ptm; -} - -static struct tm *gmtime(const time_t *ptime, struct tm *ptm) { - // FIXME(lsm): fix this. - return localtime(ptime, ptm); -} - -static size_t strftime(char *dst, size_t dst_size, const char *fmt, - const struct tm *tm) { - (void) snprintf(dst, dst_size, "implement strftime() for WinCE"); - return 0; -} -#endif - -static int mg_rename(const char* oldname, const char* newname) { - wchar_t woldbuf[PATH_MAX]; - wchar_t wnewbuf[PATH_MAX]; - - to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf)); - to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf)); - - return MoveFileW(woldbuf, wnewbuf) ? 0 : -1; -} - - -static FILE *mg_fopen(const char *path, const char *mode) { - wchar_t wbuf[PATH_MAX], wmode[20]; - - to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); - MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode)); - - return _wfopen(wbuf, wmode); -} - -static int mg_stat(const char *path, struct mgstat *stp) { - int ok = -1; // Error - wchar_t wbuf[PATH_MAX]; - WIN32_FILE_ATTRIBUTE_DATA info; - - to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); - - if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) { - stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh); - stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime, - info.ftLastWriteTime.dwHighDateTime); - stp->is_directory = - info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; - ok = 0; // Success - } - - return ok; -} - -static int mg_remove(const char *path) { - wchar_t wbuf[PATH_MAX]; - to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); - return DeleteFileW(wbuf) ? 0 : -1; -} - -static int mg_mkdir(const char *path, int mode) { - char buf[PATH_MAX]; - wchar_t wbuf[PATH_MAX]; - - mode = 0; // Unused - mg_strlcpy(buf, path, sizeof(buf)); - change_slashes_to_backslashes(buf); - - (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)); - - return CreateDirectoryW(wbuf, NULL) ? 0 : -1; -} - -// Implementation of POSIX opendir/closedir/readdir for Windows. -static DIR * opendir(const char *name) { - DIR *dir = NULL; - wchar_t wpath[PATH_MAX]; - DWORD attrs; - - if (name == NULL) { - SetLastError(ERROR_BAD_ARGUMENTS); - } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - } else { - to_unicode(name, wpath, ARRAY_SIZE(wpath)); - attrs = GetFileAttributesW(wpath); - if (attrs != 0xFFFFFFFF && - ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) { - (void) wcscat(wpath, L"\\*"); - dir->handle = FindFirstFileW(wpath, &dir->info); - dir->result.d_name[0] = '\0'; - } else { - free(dir); - dir = NULL; - } - } - - return dir; -} - -static int closedir(DIR *dir) { - int result = 0; - - if (dir != NULL) { - if (dir->handle != INVALID_HANDLE_VALUE) - result = FindClose(dir->handle) ? 0 : -1; - - free(dir); - } else { - result = -1; - SetLastError(ERROR_BAD_ARGUMENTS); - } - - return result; -} - -static struct dirent *readdir(DIR *dir) { - struct dirent *result = 0; - - if (dir) { - if (dir->handle != INVALID_HANDLE_VALUE) { - result = &dir->result; - (void) WideCharToMultiByte(CP_UTF8, 0, - dir->info.cFileName, -1, result->d_name, - sizeof(result->d_name), NULL, NULL); - - if (!FindNextFileW(dir->handle, &dir->info)) { - (void) FindClose(dir->handle); - dir->handle = INVALID_HANDLE_VALUE; - } - - } else { - SetLastError(ERROR_FILE_NOT_FOUND); - } - } else { - SetLastError(ERROR_BAD_ARGUMENTS); - } - - return result; -} - -#define set_close_on_exec(fd) // No FD_CLOEXEC on Windows - -int mg_start_thread(mg_thread_func_t f, void *p) { - return _beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0; -} - -static HANDLE dlopen(const char *dll_name, int flags) { - wchar_t wbuf[PATH_MAX]; - flags = 0; // Unused - to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf)); - return LoadLibraryW(wbuf); -} - -#if !defined(NO_CGI) -#define SIGKILL 0 -static int kill(pid_t pid, int sig_num) { - (void) TerminateProcess(pid, sig_num); - (void) CloseHandle(pid); - return 0; -} - -static pid_t spawn_process(struct mg_connection *conn, const char *prog, - char *envblk, char *envp[], int fd_stdin, - int fd_stdout, const char *dir) { - HANDLE me; - char *p, *interp, cmdline[PATH_MAX], buf[PATH_MAX]; - FILE *fp; - STARTUPINFOA si = { sizeof(si) }; - PROCESS_INFORMATION pi = { 0 }; - - envp = NULL; // Unused - - // TODO(lsm): redirect CGI errors to the error log file - si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - - me = GetCurrentProcess(); - (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me, - &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS); - (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me, - &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS); - - // If CGI file is a script, try to read the interpreter line - interp = conn->ctx->config[CGI_INTERPRETER]; - if (interp == NULL) { - buf[2] = '\0'; - mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%c%s", dir, DIRSEP, prog); - if ((fp = fopen(cmdline, "r")) != NULL) { - (void) fgets(buf, sizeof(buf), fp); - if (buf[0] != '#' || buf[1] != '!') { - // First line does not start with "#!". Do not set interpreter. - buf[2] = '\0'; - } else { - // Trim whitespace in interpreter name - for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) { - *p = '\0'; - } - } - (void) fclose(fp); - } - interp = buf + 2; - } - - (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s%c%s", - interp, interp[0] == '\0' ? "" : " ", dir, DIRSEP, prog); - - DEBUG_TRACE(("Running [%s]", cmdline)); - if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, - CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) { - cry(conn, "%s: CreateProcess(%s): %d", - __func__, cmdline, ERRNO); - pi.hProcess = (pid_t) -1; - } - - // Always close these to prevent handle leakage. - (void) close(fd_stdin); - (void) close(fd_stdout); - - (void) CloseHandle(si.hStdOutput); - (void) CloseHandle(si.hStdInput); - (void) CloseHandle(pi.hThread); - - return (pid_t) pi.hProcess; -} -#endif // !NO_CGI - -static int set_non_blocking_mode(SOCKET sock) { - unsigned long on = 1; - return ioctlsocket(sock, FIONBIO, &on); -} - -#else -static int mg_stat(const char *path, struct mgstat *stp) { - struct stat st; - int ok; - - if (stat(path, &st) == 0) { - ok = 0; - stp->size = st.st_size; - stp->mtime = st.st_mtime; - stp->is_directory = S_ISDIR(st.st_mode); - } else { - ok = -1; - } - - return ok; -} - -static void set_close_on_exec(int fd) { - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); -} - -int mg_start_thread(mg_thread_func_t func, void *param) { - pthread_t thread_id; - pthread_attr_t attr; - - (void) pthread_attr_init(&attr); - (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled - // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5); - - return pthread_create(&thread_id, &attr, func, param); -} - -#ifndef NO_CGI -static pid_t spawn_process(struct mg_connection *conn, const char *prog, - char *envblk, char *envp[], int fd_stdin, - int fd_stdout, const char *dir) { - pid_t pid; - const char *interp; - - envblk = NULL; // Unused - - if ((pid = fork()) == -1) { - // Parent - send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO)); - } else if (pid == 0) { - // Child - if (chdir(dir) != 0) { - cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO)); - } else if (dup2(fd_stdin, 0) == -1) { - cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO)); - } else if (dup2(fd_stdout, 1) == -1) { - cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO)); - } else { - (void) dup2(fd_stdout, 2); - (void) close(fd_stdin); - (void) close(fd_stdout); - - interp = conn->ctx->config[CGI_INTERPRETER]; - if (interp == NULL) { - (void) execle(prog, prog, NULL, envp); - cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO)); - } else { - (void) execle(interp, interp, prog, NULL, envp); - cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog, - strerror(ERRNO)); - } - } - exit(EXIT_FAILURE); - } - - // Parent. Close stdio descriptors - (void) close(fd_stdin); - (void) close(fd_stdout); - - return pid; -} -#endif // !NO_CGI - -static int set_non_blocking_mode(SOCKET sock) { - int flags; - - flags = fcntl(sock, F_GETFL, 0); - (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK); - - return 0; -} -#endif // _WIN32 - -// Write data to the IO channel - opened file descriptor, socket or SSL -// descriptor. Return number of bytes written. -static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, - int64_t len) { - int64_t sent; - int n, k; - - sent = 0; - while (sent < len) { - - // How many bytes we send in this iteration - k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent); - - if (ssl != NULL) { - n = SSL_write(ssl, buf + sent, k); - } else if (fp != NULL) { - n = (int) fwrite(buf + sent, 1, (size_t) k, fp); - if (ferror(fp)) - n = -1; - } else { - n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL); - } - - if (n < 0) - break; - - sent += n; - } - - return sent; -} - -// This function is needed to prevent Mongoose to be stuck in a blocking -// socket read when user requested exit. To do that, we sleep in select -// with a timeout, and when returned, check the context for the stop flag. -// If it is set, we return 0, and this means that we must not continue -// reading, must give up and close the connection and exit serving thread. -static int wait_until_socket_is_readable(struct mg_connection *conn) { - int result; - struct timeval tv; - fd_set set; - - do { - tv.tv_sec = 0; - tv.tv_usec = 300 * 1000; - FD_ZERO(&set); - FD_SET(conn->client.sock, &set); - result = select(conn->client.sock + 1, &set, NULL, NULL, &tv); - } while ((result == 0 || (result < 0 && ERRNO == EINTR)) && - conn->ctx->stop_flag == 0); - - return conn->ctx->stop_flag || result < 0 ? 0 : 1; -} - -// Read from IO channel - opened file descriptor, socket, or SSL descriptor. -// Return negative value on error, or number of bytes read on success. -static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) { - int nread; - - if (fp != NULL) { - // Use read() instead of fread(), because if we're reading from the CGI - // pipe, fread() may block until IO buffer is filled up. We cannot afford - // to block and must pass all read bytes immediately to the client. - nread = read(fileno(fp), buf, (size_t) len); - } else if (!wait_until_socket_is_readable(conn)) { - nread = -1; - } else if (conn->ssl != NULL) { - nread = SSL_read(conn->ssl, buf, len); - } else { - nread = recv(conn->client.sock, buf, (size_t) len, 0); - } - - return conn->ctx->stop_flag ? -1 : nread; -} - -int mg_read(struct mg_connection *conn, void *buf, size_t len) { - int n, buffered_len, nread; - - assert(conn->next_request != NULL && - conn->body != NULL && - conn->next_request >= conn->body); - nread = 0; - if (conn->consumed_content < conn->content_len) { - - // Adjust number of bytes to read. - int64_t to_read = conn->content_len - conn->consumed_content; - if (to_read < (int64_t) len) { - len = (size_t) to_read; - } - - // Return buffered data - buffered_len = conn->next_request - conn->body; - if (buffered_len > 0) { - if (len < (size_t) buffered_len) { - buffered_len = (int) len; - } - memcpy(buf, conn->body, (size_t) buffered_len); - len -= buffered_len; - conn->body += buffered_len; - conn->consumed_content += buffered_len; - nread += buffered_len; - buf = (char *) buf + buffered_len; - } - - // We have returned all buffered data. Read new data from the remote socket. - while (len > 0) { - n = pull(NULL, conn, (char *) buf, (int) len); - if (n < 0) { - nread = n; // Propagate the error - break; - } else if (n == 0) { - break; // No more data to read - } else { - buf = (char *) buf + n; - conn->consumed_content += n; - nread += n; - len -= n; - } - } - } - return nread; -} - -int mg_write(struct mg_connection *conn, const void *buf, size_t len) { - return (int) push(NULL, conn->client.sock, conn->ssl, (const char *) buf, - (int64_t) len); -} - -int mg_printf(struct mg_connection *conn, const char *fmt, ...) { - char mem[MG_BUF_LEN], *buf = mem; - int len; - va_list ap; - - // Print in a local buffer first, hoping that it is large enough to - // hold the whole message - va_start(ap, fmt); - len = vsnprintf(mem, sizeof(mem), fmt, ap); - va_end(ap); - - if (len <= 0) { - // vsnprintf() error, give up - len = -1; - cry(conn, "%s(%s, ...): vsnprintf() error", __func__, fmt); - } else if (len > (int) sizeof(mem) && (buf = malloc(len + 1)) != NULL) { - // Local buffer is not large enough, allocate big buffer on heap - va_start(ap, fmt); - vsnprintf(buf, len + 1, fmt, ap); - va_end(ap); - len = mg_write(conn, buf, (size_t) len); - free(buf); - } else if (len > (int) sizeof(mem)) { - // Failed to allocate large enough buffer, give up - cry(conn, "%s(%s, ...): Can't allocate %d bytes, not printing anything", - __func__, fmt, len); - len = -1; - } else { - // Copy to the local buffer succeeded - len = mg_write(conn, buf, (size_t) len); - } - - return len; -} - -// URL-decode input buffer into destination buffer. -// 0-terminate the destination buffer. Return the length of decoded data. -// form-url-encoded data differs from URI encoding in a way that it -// uses '+' as character for space, see RFC 1866 section 8.2.1 -// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt -static size_t url_decode(const char *src, size_t src_len, char *dst, - size_t dst_len, int is_form_url_encoded) { - size_t i, j; - int a, b; -#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') - - for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { - if (src[i] == '%' && - isxdigit(* (const unsigned char *) (src + i + 1)) && - isxdigit(* (const unsigned char *) (src + i + 2))) { - a = tolower(* (const unsigned char *) (src + i + 1)); - b = tolower(* (const unsigned char *) (src + i + 2)); - dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b)); - i += 2; - } else if (is_form_url_encoded && src[i] == '+') { - dst[j] = ' '; - } else { - dst[j] = src[i]; - } - } - - dst[j] = '\0'; // Null-terminate the destination - - return j; -} - -// Scan given buffer and fetch the value of the given variable. -// It can be specified in query string, or in the POST data. -// Return -1 if the variable not found, or length of the URL-decoded value -// stored in dst. The dst buffer is guaranteed to be NUL-terminated if it -// is not NULL or zero-length. If dst is NULL or zero-length, then -// -2 is returned. -int mg_get_var(const char *buf, size_t buf_len, const char *name, - char *dst, size_t dst_len) { - const char *p, *e, *s; - size_t name_len; - int len; - - if (dst == NULL || dst_len == 0) { - len = -2; - } else if (buf == NULL || name == NULL || buf_len == 0) { - len = -1; - dst[0] = '\0'; - } else { - name_len = strlen(name); - e = buf + buf_len; - len = -1; - dst[0] = '\0'; - - // buf is "var1=val1&var2=val2...". Find variable first - for (p = buf; p + name_len < e; p++) { - if ((p == buf || p[-1] == '&') && p[name_len] == '=' && - !mg_strncasecmp(name, p, name_len)) { - - // Point p to variable value - p += name_len + 1; - - // Point s to the end of the value - s = (const char *) memchr(p, '&', (size_t)(e - p)); - if (s == NULL) { - s = e; - } - assert(s >= p); - - // Decode variable into destination buffer - if ((size_t) (s - p) < dst_len) { - len = (int) url_decode(p, (size_t)(s - p), dst, dst_len, 1); - } - break; - } - } - } - - return len; -} - -int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name, - char *dst, size_t dst_size) { - const char *s, *p, *end; - int name_len, len = -1; - - dst[0] = '\0'; - if ((s = mg_get_header(conn, "Cookie")) == NULL) { - return -1; - } - - name_len = (int) strlen(cookie_name); - end = s + strlen(s); - - for (; (s = strstr(s, cookie_name)) != NULL; s += name_len) - if (s[name_len] == '=') { - s += name_len + 1; - if ((p = strchr(s, ' ')) == NULL) - p = end; - if (p[-1] == ';') - p--; - if (*s == '"' && p[-1] == '"' && p > s + 1) { - s++; - p--; - } - if ((size_t) (p - s) < dst_size) { - len = p - s; - mg_strlcpy(dst, s, (size_t) len + 1); - } - break; - } - - return len; -} - -static int convert_uri_to_file_name(struct mg_connection *conn, char *buf, - size_t buf_len, struct mgstat *st) { - struct vec a, b; - const char *rewrite, *uri = conn->request_info.uri; - char *p; - int match_len, stat_result; - - buf_len--; // This is because memmove() for PATH_INFO may shift part - // of the path one byte on the right. - mg_snprintf(conn, buf, buf_len, "%s%s", conn->ctx->config[DOCUMENT_ROOT], - uri); - - rewrite = conn->ctx->config[REWRITE]; - while ((rewrite = next_option(rewrite, &a, &b)) != NULL) { - if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) { - mg_snprintf(conn, buf, buf_len, "%.*s%s", b.len, b.ptr, uri + match_len); - break; - } - } - -#if defined(_WIN32) && !defined(__SYMBIAN32__) - //change_slashes_to_backslashes(buf); -#endif // _WIN32 - - if ((stat_result = mg_stat(buf, st)) != 0) { - // Support PATH_INFO for CGI scripts. - for (p = buf + strlen(buf); p > buf + 1; p--) { - if (*p == '/') { - *p = '\0'; - if (match_prefix(conn->ctx->config[CGI_EXTENSIONS], - strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 && - (stat_result = mg_stat(buf, st)) == 0) { - // Shift PATH_INFO block one character right, e.g. - // "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00" - // conn->path_info is pointing to the local variable "path" declared - // in handle_request(), so PATH_INFO is not valid after - // handle_request returns. - conn->path_info = p + 1; - memmove(p + 2, p + 1, strlen(p + 1) + 1); // +1 is for trailing \0 - p[1] = '/'; - break; - } else { - *p = '/'; - stat_result = -1; - } - } - } - } - - return stat_result; -} - -static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *)) { - return (conn->ssl = SSL_new(s)) != NULL && - SSL_set_fd(conn->ssl, conn->client.sock) == 1 && - func(conn->ssl) == 1; -} - -// Check whether full request is buffered. Return: -// -1 if request is malformed -// 0 if request is not yet fully buffered -// >0 actual request length, including last \r\n\r\n -static int get_request_len(const char *buf, int buflen) { - const char *s, *e; - int len = 0; - - for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++) - // Control characters are not allowed but >=128 is. - if (!isprint(* (const unsigned char *) s) && *s != '\r' && - *s != '\n' && * (const unsigned char *) s < 128) { - len = -1; - break; // [i_a] abort scan as soon as one malformed character is found; don't let subsequent \r\n\r\n win us over anyhow - } else if (s[0] == '\n' && s[1] == '\n') { - len = (int) (s - buf) + 2; - } else if (s[0] == '\n' && &s[1] < e && - s[1] == '\r' && s[2] == '\n') { - len = (int) (s - buf) + 3; - } - - return len; -} - -// Convert month to the month number. Return -1 on error, or month number -static int get_month_index(const char *s) { - size_t i; - - for (i = 0; i < ARRAY_SIZE(month_names); i++) - if (!strcmp(s, month_names[i])) - return (int) i; - - return -1; -} - -// Parse UTC date-time string, and return the corresponding time_t value. -static time_t parse_date_string(const char *datetime) { - static const unsigned short days_before_month[] = { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 - }; - char month_str[32]; - int second, minute, hour, day, month, year, leap_days, days; - time_t result = (time_t) 0; - - if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d", - &day, month_str, &year, &hour, &minute, &second) == 6) || - (sscanf(datetime, "%d %3s %d %d:%d:%d", - &day, month_str, &year, &hour, &minute, &second) == 6) || - (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d", - &day, month_str, &year, &hour, &minute, &second) == 6) || - (sscanf(datetime, "%d-%3s-%d %d:%d:%d", - &day, month_str, &year, &hour, &minute, &second) == 6)) && - year > 1970 && - (month = get_month_index(month_str)) != -1) { - year -= 1970; - leap_days = year / 4 - year / 100 + year / 400; - days = year * 365 + days_before_month[month] + (day - 1) + leap_days; - result = days * 24 * 3600 + hour * 3600 + minute * 60 + second; - } - - return result; -} - -// Protect against directory disclosure attack by removing '..', -// excessive '/' and '\' characters -static void remove_double_dots_and_double_slashes(char *s) { - char *p = s; - - while (*s != '\0') { - *p++ = *s++; - if (IS_DIRSEP_CHAR(s[-1])) { - // Skip all following slashes and backslashes - while (IS_DIRSEP_CHAR(s[0])) { - s++; - } - - // Skip all double-dots - while (*s == '.' && s[1] == '.') { - s += 2; - } - } - } - *p = '\0'; -} - -static const struct { - const char *extension; - size_t ext_len; - const char *mime_type; -} builtin_mime_types[] = { - {".html", 5, "text/html"}, - {".htm", 4, "text/html"}, - {".shtm", 5, "text/html"}, - {".shtml", 6, "text/html"}, - {".css", 4, "text/css"}, - {".js", 3, "application/x-javascript"}, - {".ico", 4, "image/x-icon"}, - {".gif", 4, "image/gif"}, - {".jpg", 4, "image/jpeg"}, - {".jpeg", 5, "image/jpeg"}, - {".png", 4, "image/png"}, - {".svg", 4, "image/svg+xml"}, - {".txt", 4, "text/plain"}, - {".torrent", 8, "application/x-bittorrent"}, - {".wav", 4, "audio/x-wav"}, - {".mp3", 4, "audio/x-mp3"}, - {".mid", 4, "audio/mid"}, - {".m3u", 4, "audio/x-mpegurl"}, - {".ram", 4, "audio/x-pn-realaudio"}, - {".xml", 4, "text/xml"}, - {".json", 5, "text/json"}, - {".xslt", 5, "application/xml"}, - {".ra", 3, "audio/x-pn-realaudio"}, - {".doc", 4, "application/msword"}, - {".exe", 4, "application/octet-stream"}, - {".zip", 4, "application/x-zip-compressed"}, - {".xls", 4, "application/excel"}, - {".tgz", 4, "application/x-tar-gz"}, - {".tar", 4, "application/x-tar"}, - {".gz", 3, "application/x-gunzip"}, - {".arj", 4, "application/x-arj-compressed"}, - {".rar", 4, "application/x-arj-compressed"}, - {".rtf", 4, "application/rtf"}, - {".pdf", 4, "application/pdf"}, - {".swf", 4, "application/x-shockwave-flash"}, - {".mpg", 4, "video/mpeg"}, - {".webm", 5, "video/webm"}, - {".mpeg", 5, "video/mpeg"}, - {".mp4", 4, "video/mp4"}, - {".m4v", 4, "video/x-m4v"}, - {".asf", 4, "video/x-ms-asf"}, - {".avi", 4, "video/x-msvideo"}, - {".bmp", 4, "image/bmp"}, - {NULL, 0, NULL} -}; - -const char *mg_get_builtin_mime_type(const char *path) { - const char *ext; - size_t i, path_len; - - path_len = strlen(path); - - for (i = 0; builtin_mime_types[i].extension != NULL; i++) { - ext = path + (path_len - builtin_mime_types[i].ext_len); - if (path_len > builtin_mime_types[i].ext_len && - mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) { - return builtin_mime_types[i].mime_type; - } - } - - return "text/plain"; -} - -// Look at the "path" extension and figure what mime type it has. -// Store mime type in the vector. -static void get_mime_type(struct mg_context *ctx, const char *path, - struct vec *vec) { - struct vec ext_vec, mime_vec; - const char *list, *ext; - size_t path_len; - - path_len = strlen(path); - - // Scan user-defined mime types first, in case user wants to - // override default mime types. - list = ctx->config[EXTRA_MIME_TYPES]; - while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) { - // ext now points to the path suffix - ext = path + path_len - ext_vec.len; - if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) { - *vec = mime_vec; - return; - } - } - - vec->ptr = mg_get_builtin_mime_type(path); - vec->len = strlen(vec->ptr); -} - -#ifndef HAVE_MD5 -typedef struct MD5Context { - uint32_t buf[4]; - uint32_t bits[2]; - unsigned char in[64]; -} MD5_CTX; - -#if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234) -#define byteReverse(buf, len) // Do nothing -#else -static void byteReverse(unsigned char *buf, unsigned longs) { - uint32_t t; - do { - t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32_t *) buf = t; - buf += 4; - } while (--longs); -} -#endif - -#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)) - -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious -// initialization constants. -static void MD5Init(MD5_CTX *ctx) { - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -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; -} - -static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) { - uint32_t t; - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) - ctx->bits[1]++; - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += t; - len -= t; - } - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += 64; - len -= 64; - } - - memcpy(ctx->in, buf, len); -} - -static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) { - unsigned count; - unsigned char *p; - - count = (ctx->bits[0] >> 3) & 0x3F; - - p = ctx->in + count; - *p++ = 0x80; - count = 64 - 1 - count; - if (count < 8) { - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - memset(ctx->in, 0, 56); - } else { - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - ((uint32_t *) ctx->in)[14] = ctx->bits[0]; - ((uint32_t *) ctx->in)[15] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset((char *) ctx, 0, sizeof(*ctx)); -} -#endif // !HAVE_MD5 - -// Stringify binary data. Output buffer must be twice as big as input, -// because each byte takes 2 bytes in string representation -static void bin2str(char *to, const unsigned char *p, size_t len) { - static const char *hex = "0123456789abcdef"; - - for (; len--; p++) { - *to++ = hex[p[0] >> 4]; - *to++ = hex[p[0] & 0x0f]; - } - *to = '\0'; -} - -// Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. -void mg_md5(char buf[33], ...) { - unsigned char hash[16]; - const char *p; - va_list ap; - MD5_CTX ctx; - - MD5Init(&ctx); - - va_start(ap, buf); - while ((p = va_arg(ap, const char *)) != NULL) { - MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p)); - } - va_end(ap); - - MD5Final(hash, &ctx); - bin2str(buf, hash, sizeof(hash)); -} - -// Check the user's password, return 1 if OK -static int check_password(const char *method, const char *ha1, const char *uri, - const char *nonce, const char *nc, const char *cnonce, - const char *qop, const char *response) { - char ha2[32 + 1], expected_response[32 + 1]; - - // Some of the parameters may be NULL - if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL || - qop == NULL || response == NULL) { - return 0; - } - - // NOTE(lsm): due to a bug in MSIE, we do not compare the URI - // TODO(lsm): check for authentication timeout - if (// strcmp(dig->uri, c->ouri) != 0 || - strlen(response) != 32 - // || now - strtoul(dig->nonce, NULL, 10) > 3600 - ) { - return 0; - } - - mg_md5(ha2, method, ":", uri, NULL); - mg_md5(expected_response, ha1, ":", nonce, ":", nc, - ":", cnonce, ":", qop, ":", ha2, NULL); - - return mg_strcasecmp(response, expected_response) == 0; -} - -// Use the global passwords file, if specified by auth_gpass option, -// or search for .htpasswd in the requested directory. -static FILE *open_auth_file(struct mg_connection *conn, const char *path) { - struct mg_context *ctx = conn->ctx; - char name[PATH_MAX]; - const char *p, *e; - struct mgstat st; - FILE *fp; - - if (ctx->config[GLOBAL_PASSWORDS_FILE] != NULL) { - // Use global passwords file - fp = mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r"); - if (fp == NULL) - cry(fc(ctx), "fopen(%s): %s", - ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO)); - } else if (!mg_stat(path, &st) && st.is_directory) { - (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s", - path, DIRSEP, PASSWORDS_FILE_NAME); - fp = mg_fopen(name, "r"); - } else { - // Try to find .htpasswd in requested directory. - for (p = path, e = p + strlen(p) - 1; e > p; e--) - if (IS_DIRSEP_CHAR(*e)) - break; - (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s", - (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME); - fp = mg_fopen(name, "r"); - } - - return fp; -} - -// Parsed Authorization header -struct ah { - char *user, *uri, *cnonce, *response, *qop, *nc, *nonce; -}; - -// Return 1 on success. Always initializes the ah structure. -static int parse_auth_header(struct mg_connection *conn, char *buf, - size_t buf_size, struct ah *ah) { - char *name, *value, *s; - const char *auth_header; - - (void) memset(ah, 0, sizeof(*ah)); - if ((auth_header = mg_get_header(conn, "Authorization")) == NULL || - mg_strncasecmp(auth_header, "Digest ", 7) != 0) { - return 0; - } - - // Make modifiable copy of the auth header - (void) mg_strlcpy(buf, auth_header + 7, buf_size); - s = buf; - - // Parse authorization header - for (;;) { - // Gobble initial spaces - while (isspace(* (unsigned char *) s)) { - s++; - } - name = skip_quoted(&s, "=", " ", 0); - // Value is either quote-delimited, or ends at first comma or space. - if (s[0] == '\"') { - s++; - value = skip_quoted(&s, "\"", " ", '\\'); - if (s[0] == ',') { - s++; - } - } else { - value = skip_quoted(&s, ", ", " ", 0); // IE uses commas, FF uses spaces - } - if (*name == '\0') { - break; - } - - if (!strcmp(name, "username")) { - ah->user = value; - } else if (!strcmp(name, "cnonce")) { - ah->cnonce = value; - } else if (!strcmp(name, "response")) { - ah->response = value; - } else if (!strcmp(name, "uri")) { - ah->uri = value; - } else if (!strcmp(name, "qop")) { - ah->qop = value; - } else if (!strcmp(name, "nc")) { - ah->nc = value; - } else if (!strcmp(name, "nonce")) { - ah->nonce = value; - } - } - - // CGI needs it as REMOTE_USER - if (ah->user != NULL) { - conn->request_info.remote_user = mg_strdup(ah->user); - } else { - return 0; - } - - return 1; -} - -// Authorize against the opened passwords file. Return 1 if authorized. -static int authorize(struct mg_connection *conn, FILE *fp) { - struct ah ah; - char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN]; - - if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) { - return 0; - } - - // Loop over passwords file - while (fgets(line, sizeof(line), fp) != NULL) { - if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) { - continue; - } - - if (!strcmp(ah.user, f_user) && - !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain)) - return check_password( - conn->request_info.request_method, - ha1, ah.uri, ah.nonce, ah.nc, ah.cnonce, ah.qop, - ah.response); - } - - return 0; -} - -// Return 1 if request is authorised, 0 otherwise. -static int check_authorization(struct mg_connection *conn, const char *path) { - FILE *fp; - char fname[PATH_MAX]; - struct vec uri_vec, filename_vec; - const char *list; - int authorized; - - fp = NULL; - authorized = 1; - - list = conn->ctx->config[PROTECT_URI]; - while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) { - if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) { - (void) mg_snprintf(conn, fname, sizeof(fname), "%.*s", - filename_vec.len, filename_vec.ptr); - if ((fp = mg_fopen(fname, "r")) == NULL) { - cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno)); - } - break; - } - } - - if (fp == NULL) { - fp = open_auth_file(conn, path); - } - - if (fp != NULL) { - authorized = authorize(conn, fp); - (void) fclose(fp); - } - - return authorized; -} - -static void send_authorization_request(struct mg_connection *conn) { - conn->request_info.status_code = 401; - (void) mg_printf(conn, - "HTTP/1.1 401 Unauthorized\r\n" - "Content-Length: 0\r\n" - "WWW-Authenticate: Digest qop=\"auth\", " - "realm=\"%s\", nonce=\"%lu\"\r\n\r\n", - conn->ctx->config[AUTHENTICATION_DOMAIN], - (unsigned long) time(NULL)); -} - -static int is_authorized_for_put(struct mg_connection *conn) { - FILE *fp; - int ret = 0; - - fp = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ? NULL : - mg_fopen(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE], "r"); - - if (fp != NULL) { - ret = authorize(conn, fp); - (void) fclose(fp); - } - - return ret; -} - -int mg_modify_passwords_file(const char *fname, const char *domain, - const char *user, const char *pass) { - int found; - char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX]; - FILE *fp, *fp2; - - found = 0; - fp = fp2 = NULL; - - // Regard empty password as no password - remove user record. - if (pass != NULL && pass[0] == '\0') { - pass = NULL; - } - - (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname); - - // Create the file if does not exist - if ((fp = mg_fopen(fname, "a+")) != NULL) { - (void) fclose(fp); - } - - // Open the given file and temporary file - if ((fp = mg_fopen(fname, "r")) == NULL) { - return 0; - } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) { - fclose(fp); - return 0; - } - - // Copy the stuff to temporary file - while (fgets(line, sizeof(line), fp) != NULL) { - if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) { - continue; - } - - if (!strcmp(u, user) && !strcmp(d, domain)) { - found++; - if (pass != NULL) { - mg_md5(ha1, user, ":", domain, ":", pass, NULL); - fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); - } - } else { - (void) fprintf(fp2, "%s", line); - } - } - - // If new user, just add it - if (!found && pass != NULL) { - mg_md5(ha1, user, ":", domain, ":", pass, NULL); - (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); - } - - // Close files - (void) fclose(fp); - (void) fclose(fp2); - - // Put the temp file in place of real file - (void) mg_remove(fname); - (void) mg_rename(tmp, fname); - - return 1; -} - -struct de { - struct mg_connection *conn; - char *file_name; - struct mgstat st; -}; - -static void url_encode(const char *src, char *dst, size_t dst_len) { - static const char *dont_escape = "._-$,;~()"; - static const char *hex = "0123456789abcdef"; - const char *end = dst + dst_len - 1; - - for (; *src != '\0' && dst < end; src++, dst++) { - if (isalnum(*(const unsigned char *) src) || - strchr(dont_escape, * (const unsigned char *) src) != NULL) { - *dst = *src; - } else if (dst + 2 < end) { - dst[0] = '%'; - dst[1] = hex[(* (const unsigned char *) src) >> 4]; - dst[2] = hex[(* (const unsigned char *) src) & 0xf]; - dst += 2; - } - } - - *dst = '\0'; -} - -static void print_dir_entry(struct de *de) { - char size[64], mod[64], href[PATH_MAX]; - - if (de->st.is_directory) { - (void) mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]"); - } else { - // We use (signed) cast below because MSVC 6 compiler cannot - // convert unsigned __int64 to double. Sigh. - if (de->st.size < 1024) { - (void) mg_snprintf(de->conn, size, sizeof(size), - "%lu", (unsigned long) de->st.size); - } else if (de->st.size < 1024 * 1024) { - (void) mg_snprintf(de->conn, size, sizeof(size), - "%.1fk", (double) de->st.size / 1024.0); - } else if (de->st.size < 1024 * 1024 * 1024) { - (void) mg_snprintf(de->conn, size, sizeof(size), - "%.1fM", (double) de->st.size / 1048576); - } else { - (void) mg_snprintf(de->conn, size, sizeof(size), - "%.1fG", (double) de->st.size / 1073741824); - } - } - (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.mtime)); - url_encode(de->file_name, href, sizeof(href)); - de->conn->num_bytes_sent += mg_printf(de->conn, - "%s%s" - " %s  %s\n", - de->conn->request_info.uri, href, de->st.is_directory ? "/" : "", - de->file_name, de->st.is_directory ? "/" : "", mod, size); -} - -// This function is called from send_directory() and used for -// sorting directory entries by size, or name, or modification time. -// On windows, __cdecl specification is needed in case if project is built -// with __stdcall convention. qsort always requires __cdels callback. -static int WINCDECL compare_dir_entries(const void *p1, const void *p2) { - const struct de *a = (const struct de *) p1, *b = (const struct de *) p2; - const char *query_string = a->conn->request_info.query_string; - int cmp_result = 0; - - if (query_string == NULL) { - query_string = "na"; - } - - if (a->st.is_directory && !b->st.is_directory) { - return -1; // Always put directories on top - } else if (!a->st.is_directory && b->st.is_directory) { - return 1; // Always put directories on top - } else if (*query_string == 'n') { - cmp_result = strcmp(a->file_name, b->file_name); - } else if (*query_string == 's') { - cmp_result = a->st.size == b->st.size ? 0 : - a->st.size > b->st.size ? 1 : -1; - } else if (*query_string == 'd') { - cmp_result = a->st.mtime == b->st.mtime ? 0 : - a->st.mtime > b->st.mtime ? 1 : -1; - } - - return query_string[1] == 'd' ? -cmp_result : cmp_result; -} - -static int must_hide_file(struct mg_connection *conn, const char *path) { - const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$"; - const char *pattern = conn->ctx->config[HIDE_FILES]; - return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 || - (pattern != NULL && match_prefix(pattern, strlen(pattern), path) > 0); -} - -static int scan_directory(struct mg_connection *conn, const char *dir, - void *data, void (*cb)(struct de *, void *)) { - char path[PATH_MAX]; - struct dirent *dp; - DIR *dirp; - struct de de; - - if ((dirp = opendir(dir)) == NULL) { - return 0; - } else { - de.conn = conn; - - while ((dp = readdir(dirp)) != NULL) { - // Do not show current dir and hidden files - if (!strcmp(dp->d_name, ".") || - !strcmp(dp->d_name, "..") || - must_hide_file(conn, dp->d_name)) { - continue; - } - - mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, DIRSEP, dp->d_name); - - // If we don't memset stat structure to zero, mtime will have - // garbage and strftime() will segfault later on in - // print_dir_entry(). memset is required only if mg_stat() - // fails. For more details, see - // http://code.google.com/p/mongoose/issues/detail?id=79 - if (mg_stat(path, &de.st) != 0) { - memset(&de.st, 0, sizeof(de.st)); - } - de.file_name = dp->d_name; - - cb(&de, data); - } - (void) closedir(dirp); - } - return 1; -} - -struct dir_scan_data { - struct de *entries; - int num_entries; - int arr_size; -}; - -static void dir_scan_callback(struct de *de, void *data) { - struct dir_scan_data *dsd = (struct dir_scan_data *) data; - - if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) { - dsd->arr_size *= 2; - dsd->entries = (struct de *) realloc(dsd->entries, dsd->arr_size * - sizeof(dsd->entries[0])); - } - if (dsd->entries == NULL) { - // TODO(lsm): propagate an error to the caller - dsd->num_entries = 0; - } else { - dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name); - dsd->entries[dsd->num_entries].st = de->st; - dsd->entries[dsd->num_entries].conn = de->conn; - dsd->num_entries++; - } -} - -static void handle_directory_request(struct mg_connection *conn, - const char *dir) { - int i, sort_direction; - struct dir_scan_data data = { NULL, 0, 128 }; - - if (!scan_directory(conn, dir, &data, dir_scan_callback)) { - send_http_error(conn, 500, "Cannot open directory", - "Error: opendir(%s): %s", dir, strerror(ERRNO)); - return; - } - - sort_direction = conn->request_info.query_string != NULL && - conn->request_info.query_string[1] == 'd' ? 'a' : 'd'; - - conn->must_close = 1; - mg_printf(conn, "%s", - "HTTP/1.1 200 OK\r\n" - "Connection: close\r\n" - "Content-Type: text/html; charset=utf-8\r\n\r\n"); - - conn->num_bytes_sent += mg_printf(conn, - "Index of %s" - "" - "

Index of %s

"
-      ""
-      ""
-      ""
-      "",
-      conn->request_info.uri, conn->request_info.uri,
-      sort_direction, sort_direction, sort_direction);
-
-  // Print first entry - link to a parent directory
-  conn->num_bytes_sent += mg_printf(conn,
-      ""
-      "\n",
-      conn->request_info.uri, "..", "Parent directory", "-", "-");
-
-  // Sort and print directory entries
-  qsort(data.entries, (size_t) data.num_entries, sizeof(data.entries[0]),
-        compare_dir_entries);
-  for (i = 0; i < data.num_entries; i++) {
-    print_dir_entry(&data.entries[i]);
-    free(data.entries[i].file_name);
-  }
-  free(data.entries);
-
-  conn->num_bytes_sent += mg_printf(conn, "%s", "
NameModifiedSize

%s %s  %s
"); - conn->request_info.status_code = 200; -} - -// Send len bytes from the opened file to the client. -static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) { - char buf[MG_BUF_LEN]; - int to_read, num_read, num_written; - - while (len > 0) { - // Calculate how much to read from the file in the buffer - to_read = sizeof(buf); - if ((int64_t) to_read > len) { - to_read = (int) len; - } - - // Read from file, exit the loop on error - if ((num_read = fread(buf, 1, (size_t)to_read, fp)) <= 0) { - break; - } - - // Send read bytes to the client, exit the loop on error - if ((num_written = mg_write(conn, buf, (size_t)num_read)) != num_read) { - break; - } - - // Both read and were successful, adjust counters - conn->num_bytes_sent += num_written; - len -= num_written; - } -} - -static int parse_range_header(const char *header, int64_t *a, int64_t *b) { - return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b); -} - -static void gmt_time_string(char *buf, size_t buf_len, time_t *t) { - strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t)); -} - -static void construct_etag(char *buf, size_t buf_len, - const struct mgstat *stp) { - snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", - (unsigned long) stp->mtime, stp->size); -} - -static void handle_file_request(struct mg_connection *conn, const char *path, - struct mgstat *stp) { - char date[64], lm[64], etag[64], range[64]; - const char *msg = "OK", *hdr; - time_t curtime = time(NULL); - int64_t cl, r1, r2; - struct vec mime_vec; - FILE *fp; - int n; - - get_mime_type(conn->ctx, path, &mime_vec); - cl = stp->size; - conn->request_info.status_code = 200; - range[0] = '\0'; - - if ((fp = mg_fopen(path, "rb")) == NULL) { - send_http_error(conn, 500, http_500_error, - "fopen(%s): %s", path, strerror(ERRNO)); - return; - } - set_close_on_exec(fileno(fp)); - - // If Range: header specified, act accordingly - r1 = r2 = 0; - hdr = mg_get_header(conn, "Range"); - if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0) { - conn->request_info.status_code = 206; - (void) fseeko(fp, r1, SEEK_SET); - cl = n == 2 ? r2 - r1 + 1: cl - r1; - (void) mg_snprintf(conn, range, sizeof(range), - "Content-Range: bytes " - "%" INT64_FMT "-%" - INT64_FMT "/%" INT64_FMT "\r\n", - r1, r1 + cl - 1, stp->size); - msg = "Partial Content"; - } - - // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 - gmt_time_string(date, sizeof(date), &curtime); - gmt_time_string(lm, sizeof(lm), &stp->mtime); - construct_etag(etag, sizeof(etag), stp); - - (void) mg_printf(conn, - "HTTP/1.1 %d %s\r\n" - "Date: %s\r\n" - "Last-Modified: %s\r\n" - "Etag: %s\r\n" - "Content-Type: %.*s\r\n" - "Content-Length: %" INT64_FMT "\r\n" - "Connection: %s\r\n" - "Accept-Ranges: bytes\r\n" - "%s\r\n", - conn->request_info.status_code, msg, date, lm, etag, (int) mime_vec.len, - mime_vec.ptr, cl, suggest_connection_header(conn), range); - - if (strcmp(conn->request_info.request_method, "HEAD") != 0) { - send_file_data(conn, fp, cl); - } - (void) fclose(fp); -} - -void mg_send_file(struct mg_connection *conn, const char *path) { - struct mgstat st; - if (mg_stat(path, &st) == 0) { - handle_file_request(conn, path, &st); - } else { - send_http_error(conn, 404, "Not Found", "%s", "File not found"); - } -} - - -// Parse HTTP headers from the given buffer, advance buffer to the point -// where parsing stopped. -static void parse_http_headers(char **buf, struct mg_request_info *ri) { - int i; - - for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) { - ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0); - ri->http_headers[i].value = skip(buf, "\r\n"); - if (ri->http_headers[i].name[0] == '\0') - break; - ri->num_headers = i + 1; - } -} - -static int is_valid_http_method(const char *method) { - return !strcmp(method, "GET") || !strcmp(method, "POST") || - !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") || - !strcmp(method, "PUT") || !strcmp(method, "DELETE") || - !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND"); -} - -// Parse HTTP request, fill in mg_request_info structure. -// This function modifies the buffer by NUL-terminating -// HTTP request components, header names and header values. -static int parse_http_message(char *buf, int len, struct mg_request_info *ri) { - int request_length = get_request_len(buf, len); - if (request_length > 0) { - // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port - ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL; - ri->num_headers = 0; - ri->status_code = -1; - - buf[request_length - 1] = '\0'; - - // RFC says that all initial whitespaces should be ingored - while (*buf != '\0' && isspace(* (unsigned char *) buf)) { - buf++; - } - ri->request_method = skip(&buf, " "); - ri->uri = skip(&buf, " "); - ri->http_version = skip(&buf, "\r\n"); - parse_http_headers(&buf, ri); - } - return request_length; -} - -static int parse_http_request(char *buf, int len, struct mg_request_info *ri) { - int result = parse_http_message(buf, len, ri); - if (result > 0 && - is_valid_http_method(ri->request_method) && - !strncmp(ri->http_version, "HTTP/", 5)) { - ri->http_version += 5; // Skip "HTTP/" - } else { - result = -1; - } - return result; -} - -static int parse_http_response(char *buf, int len, struct mg_request_info *ri) { - int result = parse_http_message(buf, len, ri); - return result > 0 && !strncmp(ri->request_method, "HTTP/", 5) ? result : -1; -} - -// Keep reading the input (either opened file descriptor fd, or socket sock, -// or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the -// buffer (which marks the end of HTTP request). Buffer buf may already -// have some data. The length of the data is stored in nread. -// Upon every read operation, increase nread by the number of bytes read. -static int read_request(FILE *fp, struct mg_connection *conn, - char *buf, int bufsiz, int *nread) { - int request_len, n = 1; - - request_len = get_request_len(buf, *nread); - while (*nread < bufsiz && request_len == 0 && n > 0) { - n = pull(fp, conn, buf + *nread, bufsiz - *nread); - if (n > 0) { - *nread += n; - request_len = get_request_len(buf, *nread); - } - } - - if (n < 0) { - // recv() error -> propagate error; do not process a b0rked-with-very-high-probability request - return -1; - } - return request_len; -} - -// For given directory path, substitute it to valid index file. -// Return 0 if index file has been found, -1 if not found. -// If the file is found, it's stats is returned in stp. -static int substitute_index_file(struct mg_connection *conn, char *path, - size_t path_len, struct mgstat *stp) { - const char *list = conn->ctx->config[INDEX_FILES]; - struct mgstat st; - struct vec filename_vec; - size_t n = strlen(path); - int found = 0; - - // The 'path' given to us points to the directory. Remove all trailing - // directory separator characters from the end of the path, and - // then append single directory separator character. - while (n > 0 && IS_DIRSEP_CHAR(path[n - 1])) { - n--; - } - path[n] = DIRSEP; - - // Traverse index files list. For each entry, append it to the given - // path and see if the file exists. If it exists, break the loop - while ((list = next_option(list, &filename_vec, NULL)) != NULL) { - - // Ignore too long entries that may overflow path buffer - if (filename_vec.len > path_len - (n + 2)) - continue; - - // Prepare full path to the index file - (void) mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1); - - // Does it exist? - if (mg_stat(path, &st) == 0) { - // Yes it does, break the loop - *stp = st; - found = 1; - break; - } - } - - // If no index file exists, restore directory path - if (!found) { - path[n] = '\0'; - } - - return found; -} - -// Return True if we should reply 304 Not Modified. -static int is_not_modified(const struct mg_connection *conn, - const struct mgstat *stp) { - char etag[64]; - const char *ims = mg_get_header(conn, "If-Modified-Since"); - const char *inm = mg_get_header(conn, "If-None-Match"); - construct_etag(etag, sizeof(etag), stp); - return (inm != NULL && !mg_strcasecmp(etag, inm)) || - (ims != NULL && stp->mtime <= parse_date_string(ims)); -} - -static int forward_body_data(struct mg_connection *conn, FILE *fp, - SOCKET sock, SSL *ssl) { - const char *expect; - char buf[MG_BUF_LEN]; - int to_read, nread, buffered_len, success = 0; - - expect = mg_get_header(conn, "Expect"); - assert(fp != NULL); - - if (conn->content_len == -1) { - send_http_error(conn, 411, "Length Required", "%s", ""); - } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) { - send_http_error(conn, 417, "Expectation Failed", "%s", ""); - } else { - if (expect != NULL) { - (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n"); - } - - buffered_len = conn->next_request - conn->body; - assert(buffered_len >= 0); - assert(conn->consumed_content == 0); - - if (buffered_len > 0) { - if ((int64_t) buffered_len > conn->content_len) { - buffered_len = (int) conn->content_len; - } - push(fp, sock, ssl, conn->body, (int64_t) buffered_len); - conn->consumed_content += buffered_len; - conn->body += buffered_len; - } - - nread = 0; - while (conn->consumed_content < conn->content_len) { - to_read = sizeof(buf); - if ((int64_t) to_read > conn->content_len - conn->consumed_content) { - to_read = (int) (conn->content_len - conn->consumed_content); - } - nread = pull(NULL, conn, buf, to_read); - if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) { - break; - } - conn->consumed_content += nread; - } - - if (conn->consumed_content == conn->content_len) { - success = nread >= 0; - } - - // Each error code path in this function must send an error - if (!success) { - send_http_error(conn, 577, http_500_error, "%s", ""); - } - } - - return success; -} - -#if !defined(NO_CGI) -// This structure helps to create an environment for the spawned CGI program. -// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings, -// last element must be NULL. -// However, on Windows there is a requirement that all these VARIABLE=VALUE\0 -// strings must reside in a contiguous buffer. The end of the buffer is -// marked by two '\0' characters. -// We satisfy both worlds: we create an envp array (which is vars), all -// entries are actually pointers inside buf. -struct cgi_env_block { - struct mg_connection *conn; - char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer - int len; // Space taken - char *vars[MAX_CGI_ENVIR_VARS]; // char **envp - int nvars; // Number of variables -}; - -static char *addenv(struct cgi_env_block *block, - PRINTF_FORMAT_STRING(const char *fmt), ...) - PRINTF_ARGS(2, 3); - -// Append VARIABLE=VALUE\0 string to the buffer, and add a respective -// pointer into the vars array. -static char *addenv(struct cgi_env_block *block, const char *fmt, ...) { - int n, space; - char *added; - va_list ap; - - // Calculate how much space is left in the buffer - space = sizeof(block->buf) - block->len - 2; - assert(space >= 0); - - // Make a pointer to the free space int the buffer - added = block->buf + block->len; - - // Copy VARIABLE=VALUE\0 string into the free space - va_start(ap, fmt); - n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap); - va_end(ap); - - // Make sure we do not overflow buffer and the envp array - if (n > 0 && n + 1 < space && - block->nvars < (int) ARRAY_SIZE(block->vars) - 2) { - // Append a pointer to the added string into the envp array - block->vars[block->nvars++] = added; - // Bump up used length counter. Include \0 terminator - block->len += n + 1; - } else { - cry(block->conn, "%s: CGI env buffer truncated for [%s]", __func__, fmt); - } - - return added; -} - -static void prepare_cgi_environment(struct mg_connection *conn, - const char *prog, - struct cgi_env_block *blk) { - const char *s, *slash; - struct vec var_vec; - char *p, src_addr[20]; - int i; - - blk->len = blk->nvars = 0; - blk->conn = conn; - sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa); - - addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]); - addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]); - addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]); - - // Prepare the environment block - addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1"); - addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1"); - addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP - - // TODO(lsm): fix this for IPv6 case - addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port)); - - addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method); - addenv(blk, "REMOTE_ADDR=%s", src_addr); - addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port); - addenv(blk, "REQUEST_URI=%s", conn->request_info.uri); - - // SCRIPT_NAME - assert(conn->request_info.uri[0] == '/'); - slash = strrchr(conn->request_info.uri, '/'); - if ((s = strrchr(prog, '/')) == NULL) - s = prog; - addenv(blk, "SCRIPT_NAME=%.*s%s", (int) (slash - conn->request_info.uri), - conn->request_info.uri, s); - - addenv(blk, "SCRIPT_FILENAME=%s", prog); - addenv(blk, "PATH_TRANSLATED=%s", prog); - addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on"); - - if ((s = mg_get_header(conn, "Content-Type")) != NULL) - addenv(blk, "CONTENT_TYPE=%s", s); - - if (conn->request_info.query_string != NULL) - addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string); - - if ((s = mg_get_header(conn, "Content-Length")) != NULL) - addenv(blk, "CONTENT_LENGTH=%s", s); - - if ((s = getenv("PATH")) != NULL) - addenv(blk, "PATH=%s", s); - - if (conn->path_info != NULL) { - addenv(blk, "PATH_INFO=%s", conn->path_info); - } - -#if defined(_WIN32) - if ((s = getenv("COMSPEC")) != NULL) { - addenv(blk, "COMSPEC=%s", s); - } - if ((s = getenv("SYSTEMROOT")) != NULL) { - addenv(blk, "SYSTEMROOT=%s", s); - } - if ((s = getenv("SystemDrive")) != NULL) { - addenv(blk, "SystemDrive=%s", s); - } -#else - if ((s = getenv("LD_LIBRARY_PATH")) != NULL) - addenv(blk, "LD_LIBRARY_PATH=%s", s); -#endif // _WIN32 - - if ((s = getenv("PERLLIB")) != NULL) - addenv(blk, "PERLLIB=%s", s); - - if (conn->request_info.remote_user != NULL) { - addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user); - addenv(blk, "%s", "AUTH_TYPE=Digest"); - } - - // Add all headers as HTTP_* variables - for (i = 0; i < conn->request_info.num_headers; i++) { - p = addenv(blk, "HTTP_%s=%s", - conn->request_info.http_headers[i].name, - conn->request_info.http_headers[i].value); - - // Convert variable name into uppercase, and change - to _ - for (; *p != '=' && *p != '\0'; p++) { - if (*p == '-') - *p = '_'; - *p = (char) toupper(* (unsigned char *) p); - } - } - - // Add user-specified variables - s = conn->ctx->config[CGI_ENVIRONMENT]; - while ((s = next_option(s, &var_vec, NULL)) != NULL) { - addenv(blk, "%.*s", (int) var_vec.len, var_vec.ptr); - } - - blk->vars[blk->nvars++] = NULL; - blk->buf[blk->len++] = '\0'; - - assert(blk->nvars < (int) ARRAY_SIZE(blk->vars)); - assert(blk->len > 0); - assert(blk->len < (int) sizeof(blk->buf)); -} - -static void handle_cgi_request(struct mg_connection *conn, const char *prog) { - int headers_len, data_len, i, fd_stdin[2], fd_stdout[2]; - const char *status, *status_text; - char buf[16384], *pbuf, dir[PATH_MAX], *p; - struct mg_request_info ri; - struct cgi_env_block blk; - FILE *in, *out; - pid_t pid; - - prepare_cgi_environment(conn, prog, &blk); - - // CGI must be executed in its own directory. 'dir' must point to the - // directory containing executable program, 'p' must point to the - // executable program name relative to 'dir'. - (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog); - if ((p = strrchr(dir, DIRSEP)) != NULL) { - *p++ = '\0'; - } else { - dir[0] = '.', dir[1] = '\0'; - p = (char *) prog; - } - - pid = (pid_t) -1; - fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1; - in = out = NULL; - - if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) { - send_http_error(conn, 500, http_500_error, - "Cannot create CGI pipe: %s", strerror(ERRNO)); - goto done; - } else if ((pid = spawn_process(conn, p, blk.buf, blk.vars, - fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) { - send_http_error(conn, 500, http_500_error, - "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO)); - goto done; - } else if ((in = fdopen(fd_stdin[1], "wb")) == NULL || - (out = fdopen(fd_stdout[0], "rb")) == NULL) { - send_http_error(conn, 500, http_500_error, - "fopen: %s", strerror(ERRNO)); - goto done; - } - - setbuf(in, NULL); - setbuf(out, NULL); - - // spawn_process() must close those! - // If we don't mark them as closed, close() attempt before - // return from this function throws an exception on Windows. - // Windows does not like when closed descriptor is closed again. - fd_stdin[0] = fd_stdout[1] = -1; - - // Send POST data to the CGI process if needed - if (!strcmp(conn->request_info.request_method, "POST") && - !forward_body_data(conn, in, INVALID_SOCKET, NULL)) { - goto done; - } - // Close so child gets an EOF. - fclose(in); - in = NULL; - - // Now read CGI reply into a buffer. We need to set correct - // status code, thus we need to see all HTTP headers first. - // Do not send anything back to client, until we buffer in all - // HTTP headers. - data_len = 0; - headers_len = read_request(out, fc(conn->ctx), buf, sizeof(buf), &data_len); - if (headers_len <= 0) { - send_http_error(conn, 500, http_500_error, - "CGI program sent malformed or too big (>%u bytes) " - "HTTP headers: [%.*s]", - (unsigned) sizeof(buf), data_len, buf); - goto done; - } - pbuf = buf; - buf[headers_len - 1] = '\0'; - parse_http_headers(&pbuf, &ri); - - // Make up and send the status line - status_text = "OK"; - if ((status = get_header(&ri, "Status")) != NULL) { - conn->request_info.status_code = atoi(status); - status_text = status; - while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') { - status_text++; - } - } else if (get_header(&ri, "Location") != NULL) { - conn->request_info.status_code = 302; - } else { - conn->request_info.status_code = 200; - } - if (get_header(&ri, "Connection") != NULL && - !mg_strcasecmp(get_header(&ri, "Connection"), "keep-alive")) { - conn->must_close = 1; - } - (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->request_info.status_code, - status_text); - - // Send headers - for (i = 0; i < ri.num_headers; i++) { - mg_printf(conn, "%s: %s\r\n", - ri.http_headers[i].name, ri.http_headers[i].value); - } - (void) mg_write(conn, "\r\n", 2); - - // Send chunk of data that may have been read after the headers - conn->num_bytes_sent += mg_write(conn, buf + headers_len, - (size_t)(data_len - headers_len)); - - // Read the rest of CGI output and send to the client - send_file_data(conn, out, INT64_MAX); - -done: - if (pid != (pid_t) -1) { - kill(pid, SIGKILL); - } - if (fd_stdin[0] != -1) { - (void) close(fd_stdin[0]); - } - if (fd_stdout[1] != -1) { - (void) close(fd_stdout[1]); - } - - if (in != NULL) { - (void) fclose(in); - } else if (fd_stdin[1] != -1) { - (void) close(fd_stdin[1]); - } - - if (out != NULL) { - (void) fclose(out); - } else if (fd_stdout[0] != -1) { - (void) close(fd_stdout[0]); - } -} -#endif // !NO_CGI - -// For a given PUT path, create all intermediate subdirectories -// for given path. Return 0 if the path itself is a directory, -// or -1 on error, 1 if OK. -static int put_dir(const char *path) { - char buf[PATH_MAX]; - const char *s, *p; - struct mgstat st; - int len, res = 1; - - for (s = p = path + 2; (p = strchr(s, DIRSEP)) != NULL; s = ++p) { - len = p - path; - if (len >= (int) sizeof(buf)) { - res = -1; - break; - } - memcpy(buf, path, len); - buf[len] = '\0'; - - // Try to create intermediate directory - DEBUG_TRACE(("mkdir(%s)", buf)); - if (mg_stat(buf, &st) == -1 && mg_mkdir(buf, 0755) != 0) { - res = -1; - break; - } - - // Is path itself a directory? - if (p[1] == '\0') { - res = 0; - } - } - - return res; -} - -static void put_file(struct mg_connection *conn, const char *path) { - struct mgstat st; - const char *range; - int64_t r1, r2; - FILE *fp; - int rc; - - conn->request_info.status_code = mg_stat(path, &st) == 0 ? 200 : 201; - - if ((rc = put_dir(path)) == 0) { - mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->request_info.status_code); - } else if (rc == -1) { - send_http_error(conn, 500, http_500_error, - "put_dir(%s): %s", path, strerror(ERRNO)); - } else if ((fp = mg_fopen(path, "wb+")) == NULL) { - send_http_error(conn, 500, http_500_error, - "fopen(%s): %s", path, strerror(ERRNO)); - } else { - set_close_on_exec(fileno(fp)); - range = mg_get_header(conn, "Content-Range"); - r1 = r2 = 0; - if (range != NULL && parse_range_header(range, &r1, &r2) > 0) { - conn->request_info.status_code = 206; - // TODO(lsm): handle seek error - (void) fseeko(fp, r1, SEEK_SET); - } - if (forward_body_data(conn, fp, INVALID_SOCKET, NULL)) - (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", - conn->request_info.status_code); - (void) fclose(fp); - } -} - -static void send_ssi_file(struct mg_connection *, const char *, FILE *, int); - -static void do_ssi_include(struct mg_connection *conn, const char *ssi, - char *tag, int include_level) { - char file_name[MG_BUF_LEN], path[PATH_MAX], *p; - FILE *fp; - - // sscanf() is safe here, since send_ssi_file() also uses buffer - // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN. - if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) { - // File name is relative to the webserver root - (void) mg_snprintf(conn, path, sizeof(path), "%s%c%s", - conn->ctx->config[DOCUMENT_ROOT], DIRSEP, file_name); - } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1) { - // File name is relative to the webserver working directory - // or it is absolute system path - (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name); - } else if (sscanf(tag, " \"%[^\"]\"", file_name) == 1) { - // File name is relative to the currect document - (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi); - if ((p = strrchr(path, DIRSEP)) != NULL) { - p[1] = '\0'; - } - (void) mg_snprintf(conn, path + strlen(path), - sizeof(path) - strlen(path), "%s", file_name); - } else { - cry(conn, "Bad SSI #include: [%s]", tag); - return; - } - - if ((fp = mg_fopen(path, "rb")) == NULL) { - cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", - tag, path, strerror(ERRNO)); - } else { - set_close_on_exec(fileno(fp)); - if (match_prefix(conn->ctx->config[SSI_EXTENSIONS], - strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) { - send_ssi_file(conn, path, fp, include_level + 1); - } else { - send_file_data(conn, fp, INT64_MAX); - } - (void) fclose(fp); - } -} - -#if !defined(NO_POPEN) -static void do_ssi_exec(struct mg_connection *conn, char *tag) { - char cmd[MG_BUF_LEN]; - FILE *fp; - - if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) { - cry(conn, "Bad SSI #exec: [%s]", tag); - } else if ((fp = popen(cmd, "r")) == NULL) { - cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO)); - } else { - send_file_data(conn, fp, INT64_MAX); - (void) pclose(fp); - } -} -#endif // !NO_POPEN - -static void send_ssi_file(struct mg_connection *conn, const char *path, - FILE *fp, int include_level) { - char buf[MG_BUF_LEN]; - int ch, len, in_ssi_tag; - - if (include_level > 10) { - cry(conn, "SSI #include level is too deep (%s)", path); - return; - } - - in_ssi_tag = 0; - len = 0; - - while ((ch = fgetc(fp)) != EOF) { - if (in_ssi_tag && ch == '>') { - in_ssi_tag = 0; - buf[len++] = (char) ch; - buf[len] = '\0'; - assert(len <= (int) sizeof(buf)); - if (len < 6 || memcmp(buf, "