diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e1bbbb..8330aa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,40 +2,16 @@ project(grive) cmake_minimum_required(VERSION 2.8) -include(FindOpenSSL) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") -############################################################################### -# finding cppunit -############################################################################### -find_path( CPPUNIT_INCLUDE_DIR cppunit/TestFixture.h /usr/include - /usr/local/include - ${CPPUNIT_PREFIX}/include ) -find_library( CPPUNIT_LIBRARY_DEBUG NAMES cppunit cppunit_dll - PATHS /usr/lib - /usr/lib64 - /usr/local/lib - /usr/local/lib64 - ${CPPUNIT_PREFIX}/lib - PATH_SUFFIXES debug ) +find_package(OpenSSL REQUIRED) +find_package(JSONC REQUIRED) +find_package(CURL REQUIRED) +find_package(CppUnit) -find_library( CPPUNIT_LIBRARY_RELEASE NAMES cppunit cppunit_dll - PATHS /usr/lib - /usr/lib64 - /usr/local/lib - /usr/local/lib64 - ${CPPUNIT_PREFIX}/lib - PATH_SUFFIXES release ) - -set( CPPUNIT_LIBRARY debug ${CPPUNIT_LIBRARY_DEBUG} - optimized ${CPPUNIT_LIBRARY_RELEASE} ) - -if ( CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY ) - message( STATUS "found cppunit" ) - set( CPPUNIT_FOUND TRUE ) +IF ( CPPUNIT_FOUND ) set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} ) -endif ( CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY ) - -############################################################################### +ENDIF ( CPPUNIT_FOUND ) include_directories( ${grive_SOURCE_DIR}/src @@ -54,7 +30,7 @@ file (GLOB UTIL_HEADERS ${grive_SOURCE_DIR}/src/util/*.hh ) -add_library( grive SHARED +add_library( fgrive SHARED src/main.cc src/drive/Collection.cc src/drive/Drive.cc @@ -67,21 +43,21 @@ add_library( grive SHARED src/util/OS.cc ) -add_executable( grive_cli +add_executable( grive src/main.cc ) -target_link_libraries( grive - curl - json +target_link_libraries( fgrive + ${CURL_LIBRARIES} + ${JSONC_LIBRARY} ${OPENSSL_LIBRARIES} ) -target_link_libraries( grive_cli - grive +target_link_libraries( grive + fgrive ) -set_target_properties(grive PROPERTIES +set_target_properties(fgrive PROPERTIES SOVERSION 0 VERSION 0.0.1 ) @@ -102,8 +78,8 @@ endif ( CPPUNIT_FOUND ) ## Install targets -install(TARGETS grive LIBRARY DESTINATION lib) -install(TARGETS grive_cli RUNTIME DESTINATION bin) +install(TARGETS fgrive LIBRARY DESTINATION lib) +install(TARGETS grive RUNTIME DESTINATION bin) install(FILES ${DRIVE_HEADERS} DESTINATION include/grive/drive) install(FILES ${PROTOCOL_HEADERS} DESTINATION include/grive/protocol) install(FILES ${UTIL_HEADERS} DESTINATION include/grive/util) diff --git a/cmake/Modules/FindCppUnit.cmake b/cmake/Modules/FindCppUnit.cmake new file mode 100644 index 0000000..4caba06 --- /dev/null +++ b/cmake/Modules/FindCppUnit.cmake @@ -0,0 +1,32 @@ +# - Find CppUnit +# http://root.cern.ch/viewvc/trunk/cint/reflex/cmake/modules/FindCppUnit.cmake +# +# This module finds an installed CppUnit package. +# +# It sets the following variables: +# CPPUNIT_FOUND - Set to false, or undefined, if CppUnit isn't found. +# CPPUNIT_INCLUDE_DIR - The CppUnit include directory. +# CPPUNIT_LIBRARY - The CppUnit library to link against. + +FIND_PATH(CPPUNIT_INCLUDE_DIR cppunit/Test.h) +FIND_LIBRARY(CPPUNIT_LIBRARY NAMES cppunit) + +IF (CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY) + SET(CPPUNIT_FOUND TRUE) +ENDIF (CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY) + +IF (CPPUNIT_FOUND) + + # show which CppUnit was found only if not quiet + IF (NOT CppUnit_FIND_QUIETLY) + MESSAGE(STATUS "Found CppUnit: ${CPPUNIT_LIBRARY}") + ENDIF (NOT CppUnit_FIND_QUIETLY) + +ELSE (CPPUNIT_FOUND) + + # fatal error if CppUnit is required but not found + IF (CppUnit_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find CppUnit") + ENDIF (CppUnit_FIND_REQUIRED) + +ENDIF (CPPUNIT_FOUND) diff --git a/cmake/Modules/FindJSONC.cmake b/cmake/Modules/FindJSONC.cmake new file mode 100644 index 0000000..f72e8ea --- /dev/null +++ b/cmake/Modules/FindJSONC.cmake @@ -0,0 +1,30 @@ +# - Find JSON-C +# This module finds an installed JSON-C package. +# +# It sets the following variables: +# JSONC_FOUND - Set to false, or undefined, if JSON-C isn't found. +# JSONC_INCLUDE_DIR - The JSON-C include directory. +# JSONC_LIBRARY - The JSON-C library to link against. + +FIND_PATH(JSONC_INCLUDE_DIR json/json.h) +FIND_LIBRARY(JSONC_LIBRARY NAMES json) + +IF (JSONC_INCLUDE_DIR AND JSONC_LIBRARY) + SET(JSONC_FOUND TRUE) +ENDIF (JSONC_INCLUDE_DIR AND JSONC_LIBRARY) + +IF (JSONC_FOUND) + + # show which JSON-C was found only if not quiet + IF (NOT JSONC_FIND_QUIETLY) + MESSAGE(STATUS "Found JSON-C: ${JSONC_LIBRARY}") + ENDIF (NOT JSONC_FIND_QUIETLY) + +ELSE (JSONC_FOUND) + + # fatal error if JSON-C is required but not found + IF (JSONC_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find JSON-C") + ENDIF (JSONC_FIND_REQUIRED) + +ENDIF (JSONC_FOUND) diff --git a/src/drive/Drive.cc b/src/drive/Drive.cc index 6d7db36..0d646aa 100644 --- a/src/drive/Drive.cc +++ b/src/drive/Drive.cc @@ -49,14 +49,9 @@ Drive::Drive( OAuth2& auth ) : Json resp = Json::Parse( http::Get( root_url + "?alt=json&showfolders=true", m_http_hdr )) ; - std::cout << http::Get( "https://docs.google.com/feeds/metadata/default", m_http_hdr ) ; - Json resume_link ; if ( resp["feed"]["link"].FindInArray( "rel", "http://schemas.google.com/g/2005#resumable-create-media", resume_link ) ) - { m_resume_link = resume_link["href"].As() ; - std::cout << "resume_link = " << resume_link << std::endl ; - } Json::Array entries = resp["feed"]["entry"].As() ; ConstructDirTree( entries ) ; @@ -215,46 +210,50 @@ std::cout << "downloading " << path << std::endl ; else { std::cout << "local " << filename << " is newer" << std::endl ; - UploadFile( entry ) ; + // re-reading the file + ifile.seekg(0) ; + + UploadFile( entry, filename, ifile.rdbuf() ) ; } } } } -void Drive::UploadFile( const Json& entry ) +void Drive::UploadFile( const Json& entry, const std::string& filename, std::streambuf *file ) { -/* std::string meta = - "" + std::string meta = + "\n" "" - "" - "Test document" + "" + filename + "" "" ; -*/ + + std::string data( + (std::istreambuf_iterator(file)), + (std::istreambuf_iterator()) ) ; + + std::ostringstream xcontent_len ; + xcontent_len << "X-Upload-Content-Length: " << data.size() ; + http::Headers hdr( m_http_hdr ) ; // hdr.push_back( "Slug: Grive Document" ) ; -// hdr.push_back( "Content-Type: application/atom+xml" ) ; - hdr.push_back( "X-Upload-Content-Type: text/plain" ) ; - hdr.push_back( "X-Upload-Content-Length: 1000" ) ; + hdr.push_back( "Content-Type: application/atom+xml" ) ; + hdr.push_back( "X-Upload-Content-Type: application/octet-stream" ) ; + hdr.push_back( xcontent_len.str() ) ; + hdr.push_back( "If-Match: " + entry["gd$etag"].As() ) ; hdr.push_back( "Expect:" ) ; -/* - std::string resp = http::PostDataWithHeader( + +/* std::string resp = http::PostDataWithHeader( m_resume_link + "?convert=false", meta, hdr ) ; */ Json resume_link = entry["link"].FindInArray( "rel", "http://schemas.google.com/g/2005#resumable-edit-media" )["href"] ; - std::cout << resume_link.As() << std::endl ; +// std::cout << resume_link.As() << std::endl ; - std::string etag = entry["gd$etag"].As() ; - std::cout << "etag = " << etag << std::endl ; - - hdr.push_back( "If-Match: " + etag ) ; - std::string resp = http::Put( resume_link.Get(), "", hdr ) ; - - std::cout << "resp " << resp << std::endl ; - std::istringstream ss( resp ) ; + std::istringstream ss( http::Put( resume_link.Get(), meta, hdr ) ) ; std::string line ; while ( std::getline( ss, line ) ) @@ -265,15 +264,13 @@ void Drive::UploadFile( const Json& entry ) std::string uplink = line.substr( location.size() ) ; uplink = uplink.substr( 0, uplink.size() -1 ) ; - std::string data( 1000, 'x' ) ; http::Headers uphdr ; - uphdr.push_back( "Content-Type: text/plain" ) ; - uphdr.push_back( "Content-Range: bytes 0-999/1000" ) ; +// uphdr.push_back( "Content-Type: application/octet-stream" ) ; +// uphdr.push_back( "Content-Range: bytes 0-999/1000" ) ; uphdr.push_back( "Expect:" ) ; uphdr.push_back( "Accept:" ) ; - std::string resp = http::Put( uplink, data, uphdr ) ; - std::cout << "put response = " << resp << std::endl ; + http::Put( uplink, data, uphdr ) ; } } } diff --git a/src/drive/Drive.hh b/src/drive/Drive.hh index c88113e..8117697 100644 --- a/src/drive/Drive.hh +++ b/src/drive/Drive.hh @@ -41,7 +41,7 @@ public : private : void UpdateFile( const Json& entry ) ; - void UploadFile( const Json& entry ) ; + void UploadFile( const Json& entry, const std::string& filename, std::streambuf *file ) ; std::string Parent( const Json& entry ) ; void ConstructDirTree( const std::vector& entries ) ; diff --git a/src/protocol/HTTP.cc b/src/protocol/HTTP.cc index 00897fb..847a689 100644 --- a/src/protocol/HTTP.cc +++ b/src/protocol/HTTP.cc @@ -51,16 +51,12 @@ size_t ReadCallback( void *ptr, std::size_t size, std::size_t nmemb, std::string assert( ptr != 0 ) ; assert( data != 0 ) ; -std::cout << "reading " << (size*nmemb) << " bytes " << data->size() << std::endl ; - std::size_t count = std::min( size * nmemb, data->size() ) ; if ( count > 0 ) { std::memcpy( ptr, &(*data)[0], count ) ; data->erase( 0, count ) ; } - -std::cout << "readed " << count << " bytes " << data->size() << std::endl ; return count ; } @@ -170,7 +166,7 @@ std::string PostData( const std::string& url, const std::string& data, const Hea curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, &post_data[0] ) ; curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_data.size() ) ; - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1 ) ; +// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1 ) ; DoCurl( curl ) ; return resp; @@ -186,7 +182,7 @@ std::string PostDataWithHeader( const std::string& url, const std::string& data, curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, &post_data[0] ) ; curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_data.size() ) ; - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L ) ; +// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L ) ; curl_easy_setopt(curl, CURLOPT_HEADER, 1L ); try @@ -224,7 +220,7 @@ std::string Put( curl_easy_setopt(curl, CURLOPT_READFUNCTION, &ReadCallback ) ; curl_easy_setopt(curl, CURLOPT_READDATA , &put_data ) ; curl_easy_setopt(curl, CURLOPT_INFILESIZE, put_data.size() ) ; - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L ) ; +// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L ) ; try { @@ -239,79 +235,6 @@ std::string Put( return resp; } -void Custom( const std::string& url, const std::string& host, const Headers& headers ) -{ - CURL *curl = curl_easy_init(); - if ( curl == 0 ) - throw std::bad_alloc() ; - - // set common options - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L ); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L ) ; - if ( curl_easy_perform( curl ) != 0 ) - throw std::runtime_error( "curl perform fail" ) ; - - long sockextr; - curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr); - curl_socket_t sockfd = sockextr ; - - struct timeval tv; - tv.tv_sec = 60 ; - tv.tv_usec = 0 ; - - fd_set infd, outfd, errfd; - FD_ZERO(&infd); - FD_ZERO(&outfd); - FD_ZERO(&errfd); - - FD_SET(sockfd, &errfd); /* always check for error */ - FD_SET(sockfd, &outfd); - if ( select(sockfd + 1, &infd, &outfd, &errfd, &tv) == -1 ) - throw std::runtime_error( "select fail" ) ; - - std::string path = url.substr( host.size() ) ; - std::cout << ("PUT " + path + "HTTP/1.1") << std::endl ; - - std::ostringstream req ; - req << ("PUT " + path + "HTTP/1.1\n") - << "Host: " << "docs.google.com" << "\n" ; - - for ( Headers::const_iterator i = headers.begin() ; i != headers.end() ; ++i ) - req << *i << '\n' ; - - std::string data = "hahaha this is the new file!!!!!" ; - req << "Content-Length: " << data.size() << '\n' - << "Content-Range: 0-" << data.size()-1 << '/' << data.size() << "\n\n\n" - << data ; - - std::string reqstr = req.str() ; - std::cout << "requesting: \n" << reqstr << std::endl ; - - std::size_t iolen ; - if ( curl_easy_send(curl, &reqstr[0], reqstr.size(), &iolen) != CURLE_OK ) - throw std::runtime_error( "cannot send" ) ; - - while ( true ) - { - char buf[1024+1] ; - FD_ZERO(&infd); - FD_ZERO(&outfd); - FD_ZERO(&errfd); - - FD_SET(sockfd, &errfd); /* always check for error */ - FD_SET(sockfd, &infd); - if ( select(sockfd + 1, &infd, &outfd, &errfd, &tv) == -1 ) - throw std::runtime_error( "select fail" ) ; - - if ( curl_easy_recv(curl, buf, 1024, &iolen) != CURLE_OK ) - throw std::runtime_error( "cannot send" ) ; - - buf[iolen] = '\0' ; - std::cout << "read: " << buf << std::endl ; - } -} - std::string Escape( const std::string& str ) { CURL *curl = curl_easy_init(); diff --git a/src/protocol/HTTP.hh b/src/protocol/HTTP.hh index df53a1e..ae6be03 100644 --- a/src/protocol/HTTP.hh +++ b/src/protocol/HTTP.hh @@ -57,8 +57,6 @@ namespace gr { namespace http const std::string& data, const Headers& hdr = Headers() ) ; - void Custom( const std::string& url, const std::string& host, const Headers& headers ) ; - std::string Escape( const std::string& str ) ; std::string Unescape( const std::string& str ) ; diff --git a/src/protocol/OAuth2.cc b/src/protocol/OAuth2.cc index 0e86db9..8026355 100644 --- a/src/protocol/OAuth2.cc +++ b/src/protocol/OAuth2.cc @@ -74,7 +74,8 @@ std::string OAuth2::MakeAuthURL( Escape( "https://www.googleapis.com/auth/userinfo.profile" ) + "+" + Escape( "https://docs.google.com/feeds/" ) + "+" + Escape( "https://docs.googleusercontent.com/" ) + "+" + - Escape( "https://spreadsheets.google.com/feeds/" ) + + Escape( "https://spreadsheets.google.com/feeds/" ) + "+" + + Escape( "https://www.googleapis.com/auth/drive.file/" ) + "&redirect_uri=urn:ietf:wg:oauth:2.0:oob" "&response_type=code" "&client_id=" + client_id ;