From 272876d2bdd283904ca2beca312dd697334535ba Mon Sep 17 00:00:00 2001 From: vitalyster Date: Tue, 2 Jun 2015 10:02:27 +0200 Subject: [PATCH 1/5] libpurple: update unseen count in conversation on active XMPP chatstate --- backends/libpurple/main.cpp | 5 +++++ backends/libpurple/purple_defs.h | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 62459980..4af24182 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -635,6 +635,11 @@ class SpectrumNetworkPlugin : public NetworkPlugin { PurpleAccount *account = m_sessions[user]; if (account) { serv_send_typing_wrapped(purple_account_get_connection_wrapped(account), buddyName.c_str(), PURPLE_NOT_TYPING); + PurpleConversation *conv = purple_find_conversation_with_account_wrapped(PURPLE_CONV_TYPE_CHAT, buddyName.c_str(), account); + if (conv) { + purple_conversation_set_data_wrapped(conv, "unseen_count", 0); + purple_conversation_update_wrapped(conv, PURPLE_CONV_UPDATE_UNSEEN); + } } } diff --git a/backends/libpurple/purple_defs.h b/backends/libpurple/purple_defs.h index f62185a4..56607ea0 100644 --- a/backends/libpurple/purple_defs.h +++ b/backends/libpurple/purple_defs.h @@ -224,6 +224,12 @@ extern purple_conversation_new_wrapped_fnc purple_conversation_new_wrapped; typedef PurpleConversationType (_cdecl * purple_conversation_get_type_wrapped_fnc)(const PurpleConversation *conv); extern purple_conversation_get_type_wrapped_fnc purple_conversation_get_type_wrapped; +typedef void (_cdecl * purple_conversation_set_data_wrapped_func)(const PurpleConversation *conv, const char *key, gpointer data); +extern purple_conversation_set_data_wrapped_func purple_conversation_set_data_wrapped; + +typedef void (_cdecl * purple_conversation_update_wrapped_func)(const PurpleConversation *conv, PurpleConversationUpdateType type); +extern purple_conversation_update_wrapped_func purple_conversation_update_wrapped; + typedef void (_cdecl * purple_conv_im_send_wrapped_fnc)(PurpleConvIm *im, const char *message); extern purple_conv_im_send_wrapped_fnc purple_conv_im_send_wrapped; @@ -524,6 +530,8 @@ extern wpurple_g_io_channel_win32_new_socket_wrapped_fnc wpurple_g_io_channel_wi #define purple_find_conversation_with_account_wrapped purple_find_conversation_with_account #define purple_conversation_new_wrapped purple_conversation_new #define purple_conversation_get_type_wrapped purple_conversation_get_type +#define purple_conversation_set_data_wrapped purple_conversation_set_data +#define purple_conversation_update_wrapped purple_conversation_update #define purple_conv_im_send_wrapped purple_conv_im_send #define purple_conv_chat_send_wrapped purple_conv_chat_send #define purple_conversation_destroy_wrapped purple_conversation_destroy From 0e94b4c7132cd683d3e81accf431947cc39ae902 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 27 Aug 2015 10:26:41 +0200 Subject: [PATCH 2/5] Find libev when the header is named ev.h --- cmake_modules/eventConfig.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake_modules/eventConfig.cmake b/cmake_modules/eventConfig.cmake index 263c0e0a..aba77891 100644 --- a/cmake_modules/eventConfig.cmake +++ b/cmake_modules/eventConfig.cmake @@ -1,4 +1,4 @@ -FIND_PATH(EVENT_INCLUDE_DIRS event.h PATH_SUFFIXES libev) +FIND_PATH(EVENT_INCLUDE_DIRS event.h ev.h PATH_SUFFIXES libev) SET(EVENT_NAMES ${EVENT_NAMES} ev libev) FIND_LIBRARY(EVENT_LIBRARIES NAMES ${EVENT_NAMES} PATH) From c0e12272b41aed4cd314001b649813d57c9a7870 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Mon, 28 Sep 2015 16:38:20 +0200 Subject: [PATCH 3/5] purple backend: Prevent hanging Vcard request when the plugin does not implement "get_info" --- backends/libpurple/main.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 4af24182..cce1f000 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -518,7 +518,11 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } m_vcards[user + name] = id; - if (CONFIG_BOOL(config, "backend.no_vcard_fetch") && name != purple_account_get_username_wrapped(account)) { + PurplePlugin *prpl = purple_find_prpl_wrapped(purple_account_get_protocol_id_wrapped(account)); + PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); + bool support_get_info = prpl_info && prpl_info->get_info; + + if (!support_get_info || (CONFIG_BOOL(config, "backend.no_vcard_fetch") && name != purple_account_get_username_wrapped(account))) { PurpleNotifyUserInfo *user_info = purple_notify_user_info_new_wrapped(); notify_user_info(purple_account_get_connection_wrapped(account), name.c_str(), user_info); purple_notify_user_info_destroy_wrapped(user_info); @@ -526,7 +530,6 @@ class SpectrumNetworkPlugin : public NetworkPlugin { else { serv_get_info_wrapped(purple_account_get_connection_wrapped(account), name.c_str()); } - } } From 5002dce4a92297c364d53872fd3a93223a31ebe7 Mon Sep 17 00:00:00 2001 From: moyamo Date: Fri, 9 Oct 2015 18:53:52 +0200 Subject: [PATCH 4/5] Prevent python plugin from crashing with InvalidWireType exception Too much data was passed to wrapper.parseFromString resulting in it trying to read another tag even after the WrapperMessage has ended --- plugin/python/NetworkPlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/python/NetworkPlugin.py b/plugin/python/NetworkPlugin.py index 717731fe..a9a20da2 100644 --- a/plugin/python/NetworkPlugin.py +++ b/plugin/python/NetworkPlugin.py @@ -319,7 +319,7 @@ class NetworkPlugin: return wrapper = protocol_pb2.WrapperMessage() - if (wrapper.ParseFromString(self.m_data[4:]) == False): + if (wrapper.ParseFromString(self.m_data[4:expected_size+4]) == False): self.m_data = self.m_data[expected_size+4:] return From a25edefbb83f130fa66cc02f661de2918965c99f Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 15 Oct 2015 16:20:02 +0300 Subject: [PATCH 5/5] CRLF -> LF --- README.win32 | 122 +- backends/frotz/CMakeLists.txt | 24 +- backends/frotz/dfrotz/CMakeLists.txt | 18 +- backends/libcommuni/CMakeLists.txt | 26 +- backends/libpurple/CMakeLists.txt | 34 +- backends/libyahoo2/CMakeLists.txt | 28 +- backends/skype/CMakeLists.txt | 18 +- backends/smstools3/CMakeLists.txt | 20 +- backends/swiften/CMakeLists.txt | 28 +- backends/template/CMakeLists.txt | 36 +- backends/twitter/libtwitcurl/HMAC_SHA1.cpp | 128 +- backends/twitter/libtwitcurl/HMAC_SHA1.h | 106 +- backends/twitter/libtwitcurl/SHA1.cpp | 548 +- backends/twitter/libtwitcurl/SHA1.h | 296 +- backends/twitter/libtwitcurl/base64.cpp | 244 +- backends/twitter/libtwitcurl/base64.h | 6 +- backends/twitter/libtwitcurl/oauthlib.cpp | 1362 +-- backends/twitter/libtwitcurl/oauthlib.h | 186 +- backends/twitter/libtwitcurl/twitcurl.cpp | 4582 ++++----- backends/twitter/libtwitcurl/twitcurl.dsp | 280 +- backends/twitter/libtwitcurl/twitcurl.dsw | 58 +- backends/twitter/libtwitcurl/twitcurl.h | 380 +- backends/twitter/libtwitcurl/twitcurl.plg | 74 +- backends/twitter/libtwitcurl/twitcurl.sln | 40 +- backends/twitter/libtwitcurl/twitcurl.vcproj | 694 +- backends/twitter/libtwitcurl/twitcurlurls.h | 312 +- backends/twitter/libtwitcurl/urlencode.cpp | 78 +- backends/twitter/libtwitcurl/urlencode.h | 18 +- include/CMakeLists.txt | 2 +- msvc-deps/sqlite3/CMakeLists.txt | 10 +- plugin/cpp/CMakeLists.txt | 76 +- plugin/python/CMakeLists.txt | 30 +- spectrum/src/CMakeLists.txt | 96 +- spectrum_manager/src/CMakeLists.txt | 22 +- spectrum_manager/src/main.cpp | 400 +- spectrum_manager/src/mongoose.c | 8944 +++++++++--------- spectrum_manager/src/mongoose.h | 602 +- 37 files changed, 9964 insertions(+), 9964 deletions(-) diff --git a/README.win32 b/README.win32 index ac932e72..cbcd990c 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 f9bc283a..b4a03314 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 3c1b722a..925e8c0a 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 9594867c..544f9162 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 c03795de..f31b1a72 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 70ffe5dc..9a569461 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 d27b4296..c9d70510 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 a557e243..84f34978 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 b605a947..f90e77ef 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/template/CMakeLists.txt b/backends/template/CMakeLists.txt index d0be90ca..6de3857e 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/libtwitcurl/HMAC_SHA1.cpp b/backends/twitter/libtwitcurl/HMAC_SHA1.cpp index 5382782e..9ed68144 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 c3846ee5..598d879c 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 e7ea00f3..a3269113 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 08951794..50006d4f 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 639e696c..ceb13579 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 00732766..aed9e43c 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 b3ec577d..5401490b 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 9ad529a7..2af67103 100644 --- a/backends/twitter/libtwitcurl/twitcurl.cpp +++ b/backends/twitter/libtwitcurl/twitcurl.cpp @@ -1,2291 +1,2291 @@ -#define NOMINMAX -#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 "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 14230b25..436cb038 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 10790bd3..6cff2fd5 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 5e491088..8d18f166 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 117e130f..d975a9ab 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 b416f7d2..ec9fbc96 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 f62da3eb..9de63b22 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 4f91961d..418151ea 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 8a906b25..59bb1468 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/include/CMakeLists.txt b/include/CMakeLists.txt index b9a3ba43..1a79f805 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1 +1 @@ -ADD_SUBDIRECTORY(transport) +ADD_SUBDIRECTORY(transport) diff --git a/msvc-deps/sqlite3/CMakeLists.txt b/msvc-deps/sqlite3/CMakeLists.txt index 7c940e54..87ae7fe3 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 75ea2aa1..4a15ba50 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 7b5fd03e..6caa1a13 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 005fbb32..eb62ae98 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 53b4e41e..ab00811e 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 58581be2..3a267b0f 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 8d52417b..8881ecb6 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, "