pax_global_header00006660000000000000000000000064117760544260014526gustar00rootroot0000000000000052 comment=93d696a527492de978a27db28e604e9f30ee1e94 Grive-grive-93d696a/000077500000000000000000000000001177605442600142635ustar00rootroot00000000000000Grive-grive-93d696a/.gitignore000066400000000000000000000000671177605442600162560ustar00rootroot00000000000000.kdev4 grive.kdev4 .DS_Store .project .cproject build/ Grive-grive-93d696a/CMakeLists.txt000066400000000000000000000001721177605442600170230ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) set( GRIVE_VERSION "0.2.0" ) add_subdirectory( libgrive ) add_subdirectory( grive ) Grive-grive-93d696a/COPYING000066400000000000000000000432541177605442600153260ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. Grive-grive-93d696a/README000066400000000000000000000036071177605442600151510ustar00rootroot00000000000000Grive 0.2.0 9 June 2012 http://www.lbreda.com/grive/ Grive is still considered experimental. It just downloads all the files in your google drive into the current directory. After you make some changes to the local files, run grive and it will upload your changes back to your google drive. New files created in local or google drive will be uploaded or downloaded respectively. Deleted files will also be "removed". Currently Grive will NOT destroy any of your files: it will only move the files to a directory named .trash, or put it in the google drive trash. You can always recover them. There are a few things that grive does not do at the moment: - wait for changes in file system to occur and upload. Grive only sync when you run it. - symbolic links support - support for Google documents - support for files >2GB Of course these will be done in future, possibly the next release. You need the following libraries: - json-c - libcurl - libstdc++ - libgcrypt - Boost (Boost filesystem and program_option are required) There are also some optional dependencies: - CppUnit (for unit tests) - libbfd (for backtrace) - binutils (for libiberty, required for compilation in OpenSUSE & ubuntu) Grive uses cmake to build, see the instructions in: http://www.lbreda.com/grive/installation for detailed procedures to compile Grive. When grive is ran for the first time, you should use the "-a" argument to grant permission to grive to access to your Google Drive. An URL should be printed. Go to the link. You will need to login to your google account if you haven't done so. After granting the permission to grive, the browser will show you an authenication code. Copy-and-paste that to the standard input of grive. If everything works fine, grive will create a .grive and a .grive_state file in your current directory. It will also start downloading files from your Google Drive to your current directory. Enjoy! Grive-grive-93d696a/cmake/000077500000000000000000000000001177605442600153435ustar00rootroot00000000000000Grive-grive-93d696a/cmake/Modules/000077500000000000000000000000001177605442600167535ustar00rootroot00000000000000Grive-grive-93d696a/cmake/Modules/FindBFD.cmake000066400000000000000000000004641177605442600211550ustar00rootroot00000000000000find_library( DL_LIBRARY NAMES dl PATH /usr/lib /usr/lib64 ) find_library( BFD_LIBRARY NAMES bfd PATH /usr/lib /usr/lib64 ) if ( DL_LIBRARY AND BFD_LIBRARY ) set( BFD_FOUND TRUE ) endif (DL_LIBRARY AND BFD_LIBRARY) if ( BFD_FOUND ) message( STATUS "Found libbfd: ${BFD_LIBRARY}") endif ( BFD_FOUND ) Grive-grive-93d696a/cmake/Modules/FindCppUnit.cmake000066400000000000000000000017571177605442600221520ustar00rootroot00000000000000# - 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) Grive-grive-93d696a/cmake/Modules/FindGDBM.cmake000066400000000000000000000022351177605442600212710ustar00rootroot00000000000000# - Find gdbm # Find the native GDBM includes and library # # GDBM_INCLUDE_DIR - where to find gdbm.h, etc. # GDBM_LIBRARIES - List of libraries when using gdbm. # GDBM_FOUND - True if gdbm found. IF (GDBM_INCLUDE_DIR) # Already in cache, be silent SET(GDBM_FIND_QUIETLY TRUE) ENDIF (GDBM_INCLUDE_DIR) FIND_PATH(GDBM_INCLUDE_DIR gdbm.h /usr/local/include /usr/include /opt/local/include ) SET(GDBM_NAMES gdbm) FIND_LIBRARY(GDBM_LIBRARY NAMES ${GDBM_NAMES} PATHS /usr/lib /usr/local/lib /opt/local/lib ) IF (GDBM_INCLUDE_DIR AND GDBM_LIBRARY) SET(GDBM_FOUND TRUE) SET( GDBM_LIBRARIES ${GDBM_LIBRARY} ) ELSE (GDBM_INCLUDE_DIR AND GDBM_LIBRARY) SET(GDBM_FOUND FALSE) SET( GDBM_LIBRARIES ) ENDIF (GDBM_INCLUDE_DIR AND GDBM_LIBRARY) IF (GDBM_FOUND) IF (NOT GDBM_FIND_QUIETLY) MESSAGE(STATUS "Found GDBM: ${GDBM_LIBRARY}") ENDIF (NOT GDBM_FIND_QUIETLY) ELSE (GDBM_FOUND) IF (GDBM_FIND_REQUIRED) MESSAGE(STATUS "Looked for gdbm libraries named ${GDBMS_NAMES}.") MESSAGE(FATAL_ERROR "Could NOT find gdbm library") ENDIF (GDBM_FIND_REQUIRED) ENDIF (GDBM_FOUND) MARK_AS_ADVANCED( GDBM_LIBRARY GDBM_INCLUDE_DIR ) Grive-grive-93d696a/cmake/Modules/FindIberty.cmake000066400000000000000000000010301177605442600220060ustar00rootroot00000000000000# - Find Iberty # This module finds libiberty. # # It sets the following variables: # IBERTY_LIBRARY - The JSON-C library to link against. FIND_LIBRARY( IBERTY_LIBRARY NAMES iberty ) IF (IBERTY_LIBRARY) # show which JSON-C was found only if not quiet MESSAGE( STATUS "Found libiberty: ${IBERTY_LIBRARY}") SET(IBERTY_FOUND TRUE) ELSE (IBERTY_LIBRARY) IF ( IBERTY_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find libiberty. try to install binutil-devel?") ENDIF (IBERTY_FIND_REQUIRED) ENDIF (IBERTY_LIBRARY) Grive-grive-93d696a/cmake/Modules/FindJSONC.cmake000066400000000000000000000015531177605442600214360ustar00rootroot00000000000000# - 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) Grive-grive-93d696a/cmake/Modules/FindLibGcrypt.cmake000066400000000000000000000032311177605442600224540ustar00rootroot00000000000000 # - Try to find the Gcrypt library # Once run this will define # # LIBGCRYPT_FOUND - set if the system has the gcrypt library # LIBGCRYPT_CFLAGS - the required gcrypt compilation flags # LIBGCRYPT_LIBRARIES - the linker libraries needed to use the gcrypt library # # Copyright (c) 2006 Brad Hards # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # libgcrypt is moving to pkg-config, but earlier version don't have it #search in typical paths for libgcrypt-config FIND_PROGRAM(LIBGCRYPTCONFIG_EXECUTABLE NAMES libgcrypt-config) #reset variables set(LIBGCRYPT_LIBRARIES) set(LIBGCRYPT_CFLAGS) # if libgcrypt-config has been found IF(LIBGCRYPTCONFIG_EXECUTABLE) EXEC_PROGRAM(${LIBGCRYPTCONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE LIBGCRYPT_LIBRARIES) EXEC_PROGRAM(${LIBGCRYPTCONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE LIBGCRYPT_CFLAGS) IF(${LIBGCRYPT_CFLAGS} MATCHES "\n") SET(LIBGCRYPT_CFLAGS " ") ENDIF(${LIBGCRYPT_CFLAGS} MATCHES "\n") IF(LIBGCRYPT_LIBRARIES AND LIBGCRYPT_CFLAGS) SET(LIBGCRYPT_FOUND TRUE) ENDIF(LIBGCRYPT_LIBRARIES AND LIBGCRYPT_CFLAGS) ENDIF(LIBGCRYPTCONFIG_EXECUTABLE) if (LIBGCRYPT_FOUND) if (NOT LibGcrypt_FIND_QUIETLY) message(STATUS "Found libgcrypt: ${LIBGCRYPT_LIBRARIES}") endif (NOT LibGcrypt_FIND_QUIETLY) else (LIBGCRYPT_FOUND) if (LibGcrypt_FIND_REQUIRED) message(FATAL_ERROR "Could not find libgcrypt libraries") endif (LibGcrypt_FIND_REQUIRED) endif (LIBGCRYPT_FOUND) MARK_AS_ADVANCED(LIBGCRYPT_CFLAGS LIBGCRYPT_LIBRARIES) Grive-grive-93d696a/grive/000077500000000000000000000000001177605442600153775ustar00rootroot00000000000000Grive-grive-93d696a/grive/CMakeLists.txt000066400000000000000000000010771177605442600201440ustar00rootroot00000000000000project( grive ) find_package(Boost COMPONENTS program_options REQUIRED) include_directories( ${grive_SOURCE_DIR}/../libgrive/src ${OPT_INCS} ) add_definitions( -DVERSION="${GRIVE_VERSION}" ) file (GLOB GRIVE_EXE_SRC ${grive_SOURCE_DIR}/src/*.cc ) add_executable( grive_executable ${GRIVE_EXE_SRC} ) target_link_libraries( grive_executable ${Boost_LIBRARIES} grive ) set_target_properties( grive_executable PROPERTIES OUTPUT_NAME grive ) install(TARGETS grive_executable RUNTIME DESTINATION bin) install(FILES doc/grive.1 DESTINATION share/man/man1 ) Grive-grive-93d696a/grive/doc/000077500000000000000000000000001177605442600161445ustar00rootroot00000000000000Grive-grive-93d696a/grive/doc/grive.1000066400000000000000000000027271177605442600173520ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH "GRIVE" 1 "June 19, 2012" .SH NAME grive \- Google Drive client for GNU/Linux .SH SYNOPSIS .B grive [OPTIONS] .SH DESCRIPTION .PP .I Grive is a Google Drive (online storage service) client for GNU/Linux systems. .PP It allows the synchronization of all your files on the cloud with a directory of your choice and the upload of new files to Google Drive. .PP The options are as follows: .TP \fB\-a\fR, \fB\-\-auth\fR Requests authorization token from Google .TP \fB\-d\fR, \fB\-\-debug\fR Enable debug level messages. Implies \-V .TP \fB\-\-dry-run\fR Only detects which files are needed for download or upload without doing it .TP \fB\-f, \-\-force\fR Forces .I grive to always download a file from Google Drive instead uploading it .TP \fB\-h\fR, \fB\-\-help\fR Produces help message .TP \fB\-l\fR filename, \fB\-\-log\fR filename Set log output to .I filename .TP \fB\-v\fR, \fB\-\-version\fR Displays program version .TP \fB\-V\fR, \fB\-\-verbose\fR Verbose mode. Enables more messages than usual. .SH AUTHOR .PP The software was developed by Nestal Wan. .PP This manpage was written by José Luis Segura Lucas (josel.segura@gmx.es) .SH REPORT BUGS .PP .I https://github.com/Grive/grive .I https://groups.google.com/forum/?fromgroups#!forum/grive-devel Grive-grive-93d696a/grive/src/000077500000000000000000000000001177605442600161665ustar00rootroot00000000000000Grive-grive-93d696a/grive/src/Config.cc000066400000000000000000000025571177605442600177130ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Config.hh" #include "util/StdioFile.hh" #include namespace gr { const std::string& Config::Filename() { static const char *env_cfg = ::getenv( "GR_CONFIG" ) ; static const std::string filename = (env_cfg != 0) ? env_cfg : ".grive" ; return filename ; } Config::Config() : m_cfg( Read( Filename() ) ) { } void Config::Save( ) { StdioFile file( Filename(), 0600 ) ; m_cfg.Write( file ) ; } Json& Config::Get() { return m_cfg ; } Json Config::Read( const std::string& filename ) { try { return Json::ParseFile( filename ) ; } catch ( Exception& e ) { return Json() ; } } } // end of namespace Grive-grive-93d696a/grive/src/Config.hh000066400000000000000000000022111177605442600177100ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "util/Exception.hh" #include "protocol/Json.hh" namespace gr { class Config { public : struct Error : virtual Exception {} ; typedef boost::error_info File ; static const std::string& Filename() ; Config() ; Json& Get() ; void Save() ; private : Json Read( const std::string& filename ) ; private : Json m_cfg ; } ; } // end of namespace Grive-grive-93d696a/grive/src/main.cc000066400000000000000000000125361177605442600174300ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Config.hh" #include "drive/Drive.hh" #include "protocol/OAuth2.hh" #include "protocol/Json.hh" #include "bfd/Backtrace.hh" #include "util/Exception.hh" #include "util/log/Log.hh" #include "util/log/CompositeLog.hh" #include "util/log/DefaultLog.hh" // boost header #include #include // initializing libgcrypt, must be done in executable #include #include #include #include #include const std::string client_id = "22314510474.apps.googleusercontent.com" ; const std::string client_secret = "bl4ufi89h-9MkFlypcI7R785" ; using namespace gr ; // libgcrypt insist this to be done in application, not library void InitGCrypt() { if ( !gcry_check_version(GCRYPT_VERSION) ) throw Exception() << expt::ErrMsg( "libgcrypt version mismatch" ) ; // disable secure memory gcry_control(GCRYCTL_DISABLE_SECMEM, 0); // tell Libgcrypt that initialization has completed gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } int Main( int argc, char **argv ) { InitGCrypt() ; Config config ; std::auto_ptr comp_log(new log::CompositeLog) ; LogBase* console_log = comp_log->Add( std::auto_ptr( new log::DefaultLog ) ) ; Json options ; namespace po = boost::program_options; // construct the program options po::options_description desc( "Grive options" ); desc.add_options() ( "help,h", "Produce help message" ) ( "version,v", "Display Grive version" ) ( "auth,a", "Request authorization token" ) ( "verbose,V", "Verbose mode. Enable more messages than normal.") ( "debug,d", "Enable debug level messages. Implies -v.") ( "log,l", po::value(), "Set log output filename." ) ( "force,f", "Force grive to always download a file from Google Drive " "instead of uploading it." ) ( "dry-run", "Only detect which files need to be uploaded/downloaded, " "without actually performing them." ) ; po::variables_map vm; po::store(po::parse_command_line( argc, argv, desc), vm ); po::notify(vm); if ( vm.count("help") ) { std::cout << desc << std::endl ; return 0 ; } if ( vm.count( "auth" ) ) { std::cout << "-----------------------\n" << "Please go to this URL and get an authentication code:\n\n" << OAuth2::MakeAuthURL( client_id ) << std::endl ; std::cout << "\n-----------------------\n" << "Please input the authentication code here: " << std::endl ; std::string code ; std::cin >> code ; OAuth2 token( client_id, client_secret ) ; token.Auth( code ) ; // save to config config.Get().Add( "refresh_token", Json( token.RefreshToken() ) ) ; config.Save() ; } if ( vm.count( "log" ) ) { std::auto_ptr file_log(new log::DefaultLog( vm["log"].as() )) ; file_log->Enable( log::debug ) ; file_log->Enable( log::verbose ) ; file_log->Enable( log::info ) ; file_log->Enable( log::warning ) ; file_log->Enable( log::error ) ; file_log->Enable( log::critical ) ; // log grive version to log file file_log->Log( log::Fmt("grive version " VERSION " " __DATE__ " " __TIME__), log::verbose ) ; file_log->Log( log::Fmt("current time: %1%") % DateTime::Now(), log::verbose ) ; comp_log->Add( file_log ) ; } if ( vm.count( "version" ) ) { std::cout << "grive version " << VERSION << ' ' << __DATE__ << ' ' << __TIME__ << std::endl ; return 0 ; } if ( vm.count( "verbose" ) ) { console_log->Enable( log::verbose ) ; } if ( vm.count( "debug" ) ) { console_log->Enable( log::verbose ) ; console_log->Enable( log::debug ) ; } if ( vm.count( "force" ) ) { options.Add( "force", Json(true) ) ; } LogBase::Inst( std::auto_ptr(comp_log.release()) ) ; std::string refresh_token ; try { refresh_token = config.Get()["refresh_token"].Str() ; } catch ( Exception& e ) { Log( "Please run grive with the \"-a\" option if this is the " "first time you're accessing your Google Drive!", log::critical ) ; return -1; } OAuth2 token( refresh_token, client_id, client_secret ) ; Drive drive( token, options ) ; drive.DetectChanges() ; if ( vm.count( "dry-run" ) == 0 ) { drive.Update() ; drive.SaveState() ; } else drive.DryRun() ; config.Save() ; Log( "Finished!", log::info ) ; return 0 ; } int main( int argc, char **argv ) { try { return Main( argc, argv ) ; } catch ( Exception& e ) { Log( "exception: %1%", boost::diagnostic_information(e), log::critical ) ; } catch ( std::exception& e ) { Log( "exception: %1%", e.what(), log::critical ) ; } catch ( ... ) { Log( "unexpected exception", log::critical ) ; } return -1 ; } Grive-grive-93d696a/icon/000077500000000000000000000000001177605442600152135ustar00rootroot00000000000000Grive-grive-93d696a/icon/128x128/000077500000000000000000000000001177605442600161505ustar00rootroot00000000000000Grive-grive-93d696a/icon/128x128/128x128.png000066400000000000000000000442601177605442600176210ustar00rootroot00000000000000PNG  IHDR>asRGBbKGD pHYs  tIME3exuEtEXtCommentCreated with GIMPW IDATxieU&s}S̑s:3TJI$K6666f*`mEQ,hww.ꮵZ h le l$dɚy~ٻS zKW"2E{>7o>|;o7 +?N O$D1XPҠI Ye`Ad66%"IĈ.֋Q"y?b$oic`@v#PG$զp81*bmQd<$dĐMJbCƲ֊akXb5,lD [pb{$k\]7Qx(Ǯ|DAF_ZG6bP] մR5a<(=R !MHhpd dB(f(9837yf^Z~bo3v%lfNoD#o? 2:tCTBY@n"r>f 3^j'V <2Ө$,"$"saA@fDRWh"FD5a\)L )(.E4K 3JxzU6CxxW_,8(f2 Bj h@Ph _nO⦩-LmP쁈(Hw;@; EI- !A-WiU%tX+Y&?:-u_H 77=?2n}$ B~Ȅ0V" l,5BDD#i,`ebf0lQlo"gkgw Nly["#],6 B" D fA-w?΂Swc|Ngʭ Z)tCg5~4q,`ICOt1#ZD$KE8V, ̌ Lzd+Oݿ͞8H?JE쩋( "} I2 ^,է.s/`N^?L5ֳjLY&ff\:Sh&b_+I+zCo' JG/tlA"(M:t [*o:nK|K?ݺ'0.Xz2+iٮ6]`٦ZYZ&6֦/V0<ӏM1c[ 4cV./ΏO?}Ow8hXca%k ֊2 _KN+ݡ$<:ümdECzIg'BmQk HzD5xw5 P3,0x/=X_[zw'&ҔV.Cg.0%}^z#'p~^D6E&0-|U JN_V5Ӎss|]DrQp$%Hqƨ+HOd!Ev;Ny5S;x[mC\l|Kݘ=3, ,$d`15Q}YO긐XQ\R9Xe2ge6 "qm'2Ps VOVaygDPNENa '{0fXa3 nw#.iaK7yfCn|w8^$~! )sGj՘x8 PVz͵ol}(L[Cp/$H00Iy[|d.W b<گB<V0 at2\qcridb"@"HQ.Tyԩy|rcۊl`mR6) ;eQ' .a[ha 1eU /d[M@R0bBTR#X g'U%d^kN} `w~ֈ.,08Rao3ϡo"f= o Wj?,,=Hn(96HBΨM847 Jg:F5 _38w7 R[d|9EuEV^n+ѷ ~dj:] X'xj<d?Sak񍁿vi!ZaA0k&}~&tF'^|RXl@d5no `3/P;x qh_ſSj B%(̩h4dZ#_YhO\/C2^z"?7ofUzJY@bx">_ o`-.`1ZuwܵPJX;J f-DR!?1^2d|-BnWNp2P)]Y.R22 cFP*eGa `;9BJ3%QДXgsAf.oX.;&PnqjnRX|.`cb$CHpsb * !P_ar0e #e K)TcM p3U4G?ق[TWZT] q0 [ cf]a-,>/^T~ o/爛P2 lֿY' F"r*yqsF/.!£ﱜCC#hBpMKEX)HPQ`_^/ļ|H,!bF)-,Q .0L{/*nȡ\" 2[_<}4J^{lsКr\&ꤚ gMFIb5a!" ҢIݦ˖DXRʵv?7#ca 2R򴈄7Usr"^p[nYZN?nEeemgv9>9R-$,vɰqd-@=(R ($0 ,f֕u*aݚl6z.$vl0|EYam ^)Ȃo<#`k2-ґӭ]HDF*)UBes`$ +ʕ`yz{nn<~Q.~ُ]Q3"]|GNv (RtBkxs_=ˀpG*ȥ =2$;edJe9@q&ֵ& pR1a csϝO 㰖RmƤIa5zW7@/PD-S|wHcS{'yBlLzĭW8 Brjm PI:BJuVl#ٙv?no)ԑ[p,TECilS^B,[ +IjDԼ&9 R->9e|!qSFrW*&_S +.Fp]!$yk? >8LQ›v qa ȟ_G2vq@ﱳ݋k*aPAfʷwPc ͽ?/n lظ־3l4@~\TAKIJP@E—gAldMF)hP{ȉ74o@)^Im}lSY=hXŻrܾsz foY (/z6., ";,e9pH"p+r@Sd#-v<51gˋ5y1ﻱ(87U1Bk|@&1Kl'f`/&|&̡X|r0CS9 /$eXTt$Nw-|n5kVK? Z~pQ;hOdT}˫zb2ˏ]t >KOte4@sHQ%,J9ws@qP>yOT'!Wfû[Oh 4p{u? kDTiuq<~2brs󴵣ZE8[. +VlLOO`0S9N8N_2}bGy$*3  Go6..+ݾ:z^}O6۝ݱ<rEFvȈ$uվbP)HvBTdы+I哹lw}~sg7ZRPN_T'7J'PI:WRH J(wV)sciMO}/j{1CrHe b8+;$P(kUo@u[՞$Yꗃn-xpv>c볝4FTe~Tp+{(2[a%)2PQKqDwoyQ65#x "޴9ƟOK]jJYەR8Z9vCog0DuvϞl+[Hs|9q]CB).*_rA}x[ 7yrTfH _3x/+o{aO^E\F :y8I㫰U&νCx 1D:#aW:##S` g7o:[PJX|@%)X22*e12zO^*v""h1jjfr?T _`U@mZo엣qG S)ky-rf_1m3@*rIՈs[ fjfk:u#nmNoDw&0|"`>]+Gꊆ0H#grRVȣ"4ThhZţuvݑM\KPNJv#896g2,7YRIGyθ;a<^MXs_߹qZ0d~׽} lf0&!XlqĞ#{R26ldD!% Իok^lm8yJe1g=;wFA- mf7 sJ?X`9ㄤfq #9-66*eB VlV`;n93 WlKn烱I^OTUԐ82q'l"՞qt>yKpxyyaU$zKs17i^Fi%u<s(yBNa7M 5o:=o^xA88ۋjW-~!T)pz<\B Csj 2>t2-M֌}?nM<%TwRgr@NmJt1DIaq2Rq xԜ۔^oGՍLK!<˩$e# O;RSTGsPE0Rc"D nv1x}ه`;g_u9 Cax wc$%8rח}|Rrn9ӳS u5e G NF[lN~ =4g@3K5T%F| PѨ~0 ben??^oov-b:! 't ~ˎq.4O+LeyuKĶ@(E=e잪냻=S ;9^_kڬgH,JydE9ǕF"̑0vF̮H{Z#3!ebA(&`!؎=^4 ltt2u$lýq(!l&08DC$|dR: GNڀ A B2&Dą+P΋Y {@)<4{:` RI 34Җ2AK9c N lbp4 6(JF*O&&th%!9 Y(j@(=Ic`FWffcEo}/>tqj ;]ch5jPJ#^`>$@O{eܶTjZ I'&L(L&_"$. ~~;v]pqZ 4aa=A|;=wAtH<ƥxf߽$$xAĀ@ڇRJ{pN)*q2" œ1XP` &}p&P,BǨC(E0-!*4HJDv/Bk_7yZ+4(xZ!;^"LnϿIBi<LFZ)!&&" x[QKUp;]ݤ 9mp0iN@"a&I,p2 b}ب6Ce@8.AdCVdC I M$N_6J8#`w>F\kaa_=0 iӇ3#|ZLJw >6:<>3ӯ,iǀM &b }uyɑVS*e)A`*bdL?7`3}I\<D֨ ׵"E: L?J-0; "Ժť(GD$w~@ïC.ogはO1dnTJC 2wY!cu'Ch/ca4 ^XjdZ=(6k$q [V7AX"1%|A pt5CpU6DÁ] ;Ck$jc]򂞿:= wbe>?4D- @{0MPM|@Tes=a@'tc rAD—8H 8k ?W6&A pɽoc0 C|'?q}XX~Xcoمf(~[ScşvL`&gK8.rBvM6 ?~+mX"F7~+Xވ&Ppxͳlb,SvFGD WǾt?wܠuwK/X!Y :WA4 ,@ @I:*ua.Q&` ~mVg!\<8+ H@ą <`4?'R $&XR"it?};Oy7jFKziCLay֦LB8W6󿹄(Nw{B\rƞf'khS*QӸy;={Ig9ФG(2&~ȇx=oo\ Ќ z9¡́и 0+) lʇEȡ;AMqxvHCly kVH8 $ƤV c#xoueFYh8yhZ=x |hE$YjHPJ= 0J0AVHAd~t!lcp2$uНHX?<:邏[8vhr=PDYրJT1ʼn$ lMJ%Y$sX=lrJ&[+ /a@kƭnB#NL!>{Ş;w6BN 84c/^4^{̌fصkANUg;46K@B#EPcKʬz\m@[8$Mf֦F|8{q1G ֓a2~Ck ϯ`~i b!"LnڗqYEvƺ<052b⺅xݻcjlA褄l+c xz@5I -Yy jF@e8 $m"t4 2m`ۀ@($VRw9_uX$ YaȞQ*S9z)P~CmZ,&57SWqM{n;u# 4,zl_3e,l@f4=3̛@kW=o?)s*LԭVmx}"|rX(3($}5@?DBԃ`E5JBny0iӄMji{S#ָ:>yYΚF,zr/v`B6!$ m 6N0ٖ=IʇZ 2U5̏M VՑ0νcM8uZ68Sou0YT)p ُ1!$S b, 8ӴkdHL+A^RY|U:@X P$^ljZD%"P g(4-1T,̉#x :kIgZ \lN9Vyiʨ Q @v9"1@ n|<8s$2 I_!%YvT !{Jցy=:ZHsaa! dv.d XtC!U~3 VX,< P^;ma3cف[lҰ'pJ Ú@S te2yF(\Z`=Tx1ު}iw̅k<JlՍMKq-pc=!~V[Gy]^v= ky N 27haC<0yb<%vpguGl<.ZMv(2p{$_p= uvc+J7 30~A,"b:n&"ZAV5 ##a}p;o ys..G)+(92Qo89Gm\x iŸ4F%c ]z"c Ι!勽5338p DzF~ V}^q38ag3!00P,T 'qL<|n?>)w3?Cƽ,z@t |;n{y5֖<\C@$VpqN3-XN,DDA < 5 "vaN8ܼ/6255UG?zjxZwOkУ>4SLynSZ3 'Et` p}n;3vZ+{=@)ZLS@>|/_vN+WG981zxx"3}4G $n5-+ K'|ODؠ19^30 S='V6ů籰 !F){.՝lui\oK[!M+k?,c1dX03 0up6^sW>cyUZbyTT9zn'׋x=,2X,2:Tx` !6"X67POV6{'0HآijyVJ2>0/,n+O^Ƨ>:*iu=n0F%]gTJ͔ |L3F (~bc tD&zIDATRi' a'>'q@LVQJ:8Y%@VsΝJjZSk]Z{Zkb1Ƅ`quuG}O޳ALi f-^姂 xTV47: <8LEia}߮41Alۏh3zWW6)ȀdJ˱^ ӳ8u[m `B,cna)CuOSPD5jpI8dt;xk U&k ȱ5nH$hOnb:x]iW?={?+8 9%@]aNV~J[lOZ0ДMcF^X2B]9֥v<~l@YHg<.}֯?{YK_pxJ8 alAAOWp  g!W&_ӆ^hX/P0UhJf9AS2$丘.9ΰ8AM#V w~::G7yp{3| 1 bMsHtwy9sݖⶠ߂҃nCJPk*6N%C˪=AS4K#41M3'U"&c:.7'M戟ml*#רn/-&Fz%((^jҪ)Ɛ5lV M}}>X}i@_XSX㓳_?&! nv˝,D(X&VNZnВ{vom偯W cp Σ0x0j,?{ȨR>?eq?!a8%.Vj'&aB1̀V=P ~j_'3_ m|ZA\L"iIENDB`Grive-grive-93d696a/icon/16x16/000077500000000000000000000000001177605442600160005ustar00rootroot00000000000000Grive-grive-93d696a/icon/16x16/16x16.png000066400000000000000000000017061177605442600172770ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME8* tEXtCommentCreated with GIMPW!IDAT8};l[eqi:K ҖG *RT$ F*  l+H !@PZԐRu u}3(3o;ItB`xsvl]Y&xuTJ]?orZtSO>~D04OH bm~羝(z w!TAmټ۰ďru<43i&j(I&"f%yշV T|j۾*zOPLc9 UOALGqbQ0 m>2S J12f!訡=*UoDI|$I( "$[O˔XLZFl~f c2/J׵HI##nٗtDS_k@kbI ,B~8zA+=ZVt@ͨ@lfҫ4V.Oә0"@44C*i;;R1kϜDs\+k @>MHtrr D( :+F^[ho.9BH8wJԻ9KD,P'yxT|u!<0mVBe0MՃ0毷/Hb.DVn23b#xau&(uP̃D'ƹծ v?>;$Ul6pwd$;nkضE<4%%^Q^19Xtsk?8kǵIENDB`Grive-grive-93d696a/icon/22x22/000077500000000000000000000000001177605442600157725ustar00rootroot00000000000000Grive-grive-93d696a/icon/22x22/22x22.png000066400000000000000000000025311177605442600172600ustar00rootroot00000000000000PNG  IHDRĴl;sRGBbKGD pHYs  tIME: CtEXtCommentCreated with GIMPWIDAT8˵mhey]gg;NX|C]*Af/ "GIR`TA}ˈ ",*4Җp[se#,|\22󗏑# T( hė|b3:%Mi { *GiU~_{<*lݷsYD[_pRpQ !a{99z,ؗ7jG +f~|Ql۰6=~C8ekj cʐ={B>ry8c lbpI w!w,CSظ 4՚xti۩nQ?0/ AeFXkPIYySK!V}---o95sίؾq? \T>2bHQh2$=!H:zHR<(JRP%̔d)+;3 "NF$*N gv6 YYov,{.7^93P r'rrr[QQɝhjS'%i CDFY|o_T"U,$GIϢG UP=@):9 a:UUTt )YpIFƧˢ#_?U&l@g2U]o%%fD~y6|S09ȜF@cTZQdԐtjiR:u`3F fΪSQRTU B}T\EpJR-tEJ^8%NW3T8+T32hLj0-(#_?!K6әI".Ma )rk&̝R`dw1$0V*FrYPΊj ujjUUee.UUTk`bT9r`pcKqB>(Us#̍0W"Rtȕ̌"w\ H+S:c \)Es%qB%$P 9`+Y#Tr:>,qΈ@)&;r{j^F ad8@2 @8 Cg `\B 2\50F*h3PP !=Jxz#Ч(%Dy9" @NEdJ29,0 %,3dC2 +zkW\j`Ɔ D(roNu8yD0 s1THjuMq@\>jAx;(08Y2Ҍ   APA6 0c,U@@@Lq10\1{2Kh P(|pV;H2"W"@nDFAXR* TD^lR!G܎g3kYF~,r,|SO\G/o*lf20O7/8 M@&JFP. _On{4zjA 2V"8F0  !A1+%mƈĨ҈ЊP10B1F(ʂ"@E7RF)3BG@ (ȡ! Aȵc *%2 T$THNIA.dilp6 \SyIvBi i!i"uO" О*z.s({Ƙ_wqyz 3=F E$5V:F000`4"k/" AAl|L( *>\xC_PRzT8%`; x%WpI ăT$J&"HD 6#bU%A$$ ,VEdtW"㔺m{nǸBAG 6 Y8xdr[ɝSKRd8 c""}=gð}4}}"ҧ/~ݝk(zaHT" t FD!xBĀD%]cNT (D >&x #%Hc|O$EUM[B$B1ϒ)G ȄHCDL̬`f bff0Ol`1 ٶ Ou~⇟1g0 <ⲛ_۳1}ÃQg!!t Plm:wsIف#=#]%\̕=^ė;Bl eۀ[ 08O !Ȉ`2"   S)B?/, x R9`  * =CAOD  DP 2d "Cc%}AEY#z(kE@ح~ K|IH盵a2OIENGgD@!dx:9,M"'"b t-Pu DB 챸C|HDG ^F̂Ј "NuܼॸEd<EDbxʣ Dh,nG]XThEJRA)R*>S3dgCEL"LPN 21),&1S2ŷ.EˮXCVfm@K>Oi24uq/Kx?[ t-lEruG)h!C DB4HAms^cYm)DSFQ9稰u|.9)̕}}MR#@C.6gC$FX"5nGF$R(Jd `&SCND0QS8`ԉE>e\K|tМj6@/zttv9IB0$pn([l1'ч  "RhUhs#/@/k] *( F*7 '#Qa"Ģ2O`j,UlOb>=TbyH%eh-wEe͢;KA) }+0ŷ(d ELD3|{hH q [b2d:g.ۣ`rU W \U v vlAdH޺ ֛]{40Qy?-rߋBB\ BR@kylʯGH?GT 3cȲlf&2R RC\G4QTiv]ַFRC# žD3"}`b'`@?5nݺy0KueCd6L[w_ $;l e*w  }h> B!2alTdۜT !^p3 &?/t"K}"rQn|.E%JP!+.B*VjbPYXBȒo!E rAJ p&)SL 06cEsYߪ^"imduvzhORu; ; A 3}D$zC(#,!rϞIۑX(2:"/OxLyLR9o[rU"}uy]°T* 3ߩH1!!U@' QVPlO- r*bW6ئm!&n,xZ4N??>8>@lC&\zkS''_sNޕiv eDl"90$$ +dʇ>A΀-A5EE0 nDc:^\OЦ.§1.XQ_+>3"NjӨDf YdAKD)S*0 H @z"kv8oDgӣDQ/ȓ7 6LZ'8m/1~q.A#Ɣ}@"!P[X~[_FB#)e"G4 8|3Bg7~Ywս._*'kl_Ya"RgZ߁h}Pj \HTzzt+ +>|gihKͥa4yu$O:B@kd"Ջh}[}&e♪XV7`QT"ꔂ/='p5Ku'mR `a5[ X!5la:4YMijzY Γ"QY B%zӁY[;~'~U`Sj4 ȼ%~ȝ7ߗ-|o{F  oSJ%8#K4T_. !o$x>2IBFr>МG* .deAKjoa/0ƧҨ',B>]@Sˎ 0 2`O"̴o›=;fX8ʊ_йp6g>ޥ7F?n%.16!C !RIזS (ӸeJd:^2s;(jG+t9 20U;C?_ޢQ;\)4o`Y}Ϭ¼ E!EOHᘢk9NuX! mԷN}qvPhެ7k˯~meq<ݎ2-*THF$RemH5K#J}lJWrS`)EcIzSTރ\ ؤ XRRm.SPИEmMdtW.a>l|uvq(C`un+I6"\x?{OŚ C̢32*/(i~5SDv$D}s,DHk!'))#)WgZNͬdP{+qLpH<$StX,8}jY/bnY1&4A(D +S4&p飧g'>:9ڝfЁ%*ITTz݅4ӠRi[rBPe* MS%"H? lSE7/qNzS b1k4dEE'cX!ldkw7P4LhlC1i#^(8ÏMNt61H*B燫.*/e  b_PQOeiEek63h}n5a;3V5V|(/ dc*0ZR mΥlmYx׍7g ꍑ՞&m6"&\Z`N^积|GFtC}a` :QiaS\hW [w ,&5/+avu`2T[E^6E%ܨo>2wK_hLIn.-tH(._6yy|'I5o ں7kd[O?zrgdigEf%xYԲK)U yQhTݠ˳/F.Y1jlW))6k[j#S0$TBfdWvss<Ƀ"d*ŵldf6Lܝ#O4n,&"K{ATBP]0jRVSꋒVZ!h~u.wdX{o2&`tk%viLPj!e5aw9 4oQ $I?)aQbDMoJKiڥjhj7+#blAŶEȃR 7zrZ4Wyq˹T+ToY.hLnGKC^QL^>mR؛8ÿg?g'_>f+F ۦ\@9\;b1߸mS(Kzѭ:K܌r 4j"0fJ-jNa?|xt5q*l64KXŒ%f% ԦP6D@OC+&AʮmKh+T7iYx֨mz\u9kŘdӹ+DaV4˂Ͼ|򖰩+\zFmRG(;l:1bCW*3bt1Uh '͢29M:д4Y x%AkHJ,2X%MsYNIr-XLxqg %) aA^ IDATfv.Z^cRxLӆTK_o?9;54`E[/zIϛT4Zy uTC$4xLȔv/ŮM!Lě͏e#f[OV yç*Pev,aX3{aldOGln}OG_7'[9SR0K+u-$2Yk*\|b3-`f?iQ,*׃} /b}6`\<sNJ{PNĖin}5j"iN_J8,WW^t2O>oןœ<-hReQOVo|l/+XDЋfQE9 0{&8.t^ .iDKZpi6gkƳ?qVKV-"b02jwޘ+yU(SmO,l4?׽Gst8UXc\b̈b,fK{:W߯>C?NsXBLSI4:nlJ:(#"t-H|8[E!U5Jd^e%h(~9ɯ~ݽ~g,SV3AhMI_s?:N&?s28IcKzi%zalh.ցl Ъ,Ŏ n)v%8s}ܰm,&mjVM¥}P0/EeZ@#qpt4JNN<J5ZCk[ͨ-hNq|Ƨtc xιjjەS#΋FE|/C {޻]Bn4V3<2O=/&}KNrnJ.-s>3Xay ѪΒ Zc ::R2.t*Q*7Jb<) ͹0^F5?yuv4tl6ԃ~;'>'7Rͤ#|/@PۑΔn5zC᯺97 X7 XY*BwHl^;)LZ3rcgR!ޕ+W$,gr3=񙦧dm~c?xtqSHw`CmHz 5L `4tjSVهd7CI!|8R֔Yak"rhco_*d\fH([b Lyau*<=ـ&O̥Ҿ*MV5!\vu-b2t[og}>)49M0^ hIi{g'76!Rj=α5YzĹLx?IMG<OupffW.y8h7c)e.jlyc)6ܥ&y䲘[{+ J6.KW[h{o7=hekQ7S5˪ V$ ̬2ژP{YʛQZ<uf;r;_v+|pUvh?Sd;'G;J/dT[¦aВ[mҜ>PuC3JV]݂{bWHIM*bmsi_lAs$k]<7 B2 5TJȀq'⃆7¥ͬ*ۀb>ڷLJ<=!bUeiZ* (mh@`V^Lőmr܌ؖ@@RRԍDe>W9m8NKAw5\DIr&y (VRx4NP lg8S4~Y6t*F!j`DA(U輚e-1f}*[-JK+&˥CӰtef!NS,$'. AsOi̞&-:/|6%+J0rgou2p鉵|?_xp_>}h4,g-p>4Am%,g5Q%M^6 S1;rOE9g֧:tLK☠@>V bS}=r6|@h{d'j8d3ƻΦ(Ӽ&)U1Bk1 8]Ģ2?ZZ$ ylrcC\T4AW~,͂hvL҂QH*~m%:,I WAo%@*D(;Cw} _uG ^ŔG9d2M<<:S2ii<3kgdx)\>ѫ8f.@آRkT$:49vj ѲY{n5gute%pSxSǾ\2\1q Uṩ,8k2:ci[0LJ6 vwG#=o?v2zIN %~ԿdRVuʊR7X/_h.n Q@g\ml抍Cb.1: ?G*Z-vGš~$sfU"IY.l;Irҝ>h`4X?>;h!({S\S2<(T}']RiA@:Ä1(] kk45H0S~bZ Ė$j#"|,M,uRfN~I{.A+g))g{sͭ{G)|JxB&N>L?>qprmG(73V-N|z Q]aˉ,%)NWCJ"`Vщ&VtU 9MV[xVs.jxU{\dј{IoWn6ug3O2oξl.Z)/!aLYV3IJ,n -BY\MaiR m:WM5)HYc+ Dg33?uyC: ;5(ys$,5V[˻5]}UnbQW-̫&K4ACwi$ es\=ɰۚԁU :tڌ3HD:Jti{TJ® ߺuf6i9z*^ 6e6.SoOw'Fga|n_RlvfUZ6ǒh6F5@H,]'WBZM1dqIX7j)Fdhb^BH_EOCJG &sRVjzagÁFO$ȼJhG33M- gpiriΤ >ۜjMi\^k(b4uFJ툞7HgkK|n!mY홡%SsFti1\kï-pJ{\弒@tQbXv$FD6hZ I_#vetz7٥ws_I6AK Z5l^k<`h07 Tz"bZ^!ˊ#i-gVۭf1ˠs0qf\l K#`T{z?{Jwkѹ?W~?""~xvLӐ¥A&\t\fT*kI am6ZԬDt σs< ;.U Em*f ]-셫mPn`K,糥jvT_2Ue I?}8'Ox6wiKQKubn^ZΕPUX2oN3@tM[Ҽcʱ4 7"{@F)`wbc]qkubˊ}^ʐEۊ!L7ӳl]acf{p6NV2j eO+ B,Y DS/ HWK&+!gmjRLg#%|6pF\-6;l?Ϲ[Ye+ ظkE5F)zSp5j_,- N.G== {jZ;/ *cPF=F߀̗|+8$N2ӁS'42RevHY2g`0E՜"`PU&DVs=iaN+L/v;Nޔ7 vJj&dWYLTV7\aۦ`qEhn7G3ht-IxRV@L2~Wo4)u3mcT򎯗yb¥ft'>h2Yܑy#Wӈr尰P K٥¼ۨjkfZv+m\ۺCًs3e6Ӿ\:Dۥ\n~ږ5Kp!k]ϑnX| ݾty~r't~dyN4q2꼇&Edަ H_QXKBF+UnXh1kiaY>OV: V4N.4!-$L+ @vzA`g+2j~kjL;Hy+SI7|M61MR}؝ I6{J qd3O_=FO,F"T!/N`4FhId˜3-,ln.R ??ャIqmT%ƪVe@e}jz/F5i?5D=&@ytt;S'&yx9+.+ȗz\^ O((u⾷-א¿EҨ.^2s_x00(~73y?ۃL|0iʵ@f. ~D,v9w{^<֙% o]~> &Ӈg 6Se38'd89yfv|xhf獌5N⢇-T'=: ,s֌,-RPqNCK4>V&J } ^>yͳѽ7WN_sQk>]Rє*DDTun . 0O wk^[]y{.+"W'Ѷi5"MV׏mpO?>n&.{S,kX=LbP{/-RlsjCK&16A5peH]0| _z})i~zz._"TfƆ_Ul9OeR눬0h*H1LԞ~Cl4 |tr%viLha(-.R:ɚr8lwz]di񍫁Jc#Kg_>M@}+nBLsY3ejT8e>)v)SY0uY%Ru0>~ַ\ð ;,LS8ɿvSST(Vt)9U>oˬ0x{]PGZ_~0>!`N<+7v{U;ޫ, ,w-SL `gCnKj_XmfPlau߬&`:._Gq&MKhg7~N,+|-ق%s 7,׏>>syT7Jc[sm!!L5e[IyKLj+PBg~^;RM18SN{(}٭˗ey"%Y5-e/v9w]& ЮtP1 cDQ7Kɝ7Y7CU>hQ:)-ކ^H\j_5*Ͻ6l+,LuciU?(pek;jgr"VYL `V~d8;=^LB"+ B1v51XQ#|24m㬫({fٜTn]%Dg_ۿ^eY.I\*GnvR?y-ky{J/ T:*}ۀf5"'ۢ !`g=Hr]K~Kr4>X6zH['N<8*>`F>TgyⰭ*C.Zdm , Rj9wѽi 3ǩX}Z 46z9ھ =fܒa%q0<נVZJLzq޳4V!SRd&qØ ڤOA؍'bߠp )9qkg=4GI=HV{raG,/3ErsFIOÍ  Zk뵷?~U=̷8(o5pZ 2{a;y ԡ%II'*!߸oǧ}*^N9sq:2R<e-E-yU9u)&Y*R36)¬T.3вm]\ywteۧ.GE @^>w\bk}[TH\1 4<ѥmP=ˠS:\S]Sz);p#}wN{>滳[/SwHd+roơ8 qV)o!@2+ ]!3yE١2`|pP P)+pf]& DtpcduWb˼%1Jf.|}ui75 C6=1;nܮG1Tg`rqI~'E*XВI폮=#F2U4fAyz w 1vJ'RKTM&*yrR,sB<.K3vlt;MXFuRPxKyC7klpz |h8CI- E)<◚ S̩8 k2d~{޺O7pZIFZ eh(#5y)Eg,( TʓHdڀL\OFw:跻׶nvyT99{W{7szXlbŌ`)H,7ii,W\Gh/ɜ&Ů}=' pd¦:8}{vF8g8vG!oD[r􂹔kET,]J$γ#Ƕ5xsVp9USd1e9y뛯lsޒVWĶfCɔZ`6$5N'%b'i,2MMO*lxCw9>ȧ٦8y@.7M&\=sHD)Uv,L5qKlX Bb1h}Y&(*}az>Tι[7=6ƠCQ KJ`l;s77oJ\OeSYX}t;)D_`hP\č/mCRNP7:3:%l]26s`_yLQy3?3ET8JPD91}KRRHBTy>=3,Q8qm͉֓ c1=:{Qԑ.onO9vx\L$eLGK.^*UCiWX%nk' ʲm_<)R[VṕO:9`2`M[H!SC|ȲTHT[59ԆD GJݲMam798wy &e#N0i- UUT6]s^{סGͪ`Э; Qbwg,)N&5D(TOÔiNݣ>7x%**k6s %G tp"d=-I;_ojvQHMK+e2/-\"QZ; Jg?KYX_?fӺ*%!DuبڗBmBm9ڑͤmÙ\MT3qw%ZxAawXͲM2 '^9kX<ՠ /&?}J0pGZ ڃ!^T\E}PrZ*PV@9? % !1V ~4" k+Ŕ/Q&D\%i?gn|a^kBV!@ICϖ{xPnhЂkugo]k(Oegkfo~C!5 ԜG⮿8sBrcgA"+V^v ,"uzbz^Ii!XdY&.{Ky[/|׷w!zD8 F@`f̉Y#,kRabI#o'(rTlc':G,x_>M3o=' v>ִieoZ\T`)}~ܨR̰M-]?"o}ɭm3Ɇ=Ŵu6e >捩tTh2͌ngt:ľ cDSLDNNg/d*8cdC)(!mcvFV*S+h3y̏uo `gFO$ޔR YnIosgܨ@J"sK гa$BKT*5b1U an lDPYZ)!K6sً` )JatCVqdp,:(LH |m#Z%EPl^̿|̻a^مx]ޗzAr1MI8v#O (U(ՉU`#eZm+3Z7 1rr&p;n/ OQ6B[ wQ=Jei&~io ~_{i[KaԽ /PJRBoV.^dHwy2h$f2ksta]R]A}Ja2OQ`'zK^<ZC{NkvǘxK;pr[W[͌&oE'z>:V~ZcZUKe/xoh[Fa8}۬b+Ƀ8~+Z{gNv*EeFuJ~h󁋗;P)D4?::Ív9?^eѢ[hvQVj`˰̀בL^%q?;Q!V +k5-L0kss(7ln밆=.UBD !^[hu'$By:*a2>l޲-{a1963g|uYOZgGPve/KoQ腳Dx V t;|P`A||2t !)l&>"eVnV&fz˛1\S2J,s^5NjhȝQ`0Vo$PHIeBCf, ɒe2B\%k%E Cu:q׉QTO,)|O { sIjZQvN~"ve n,'3TH5ec㖁s`xWU֚Uy޽ ˲a7GHEuC({H; gXqwW⫊D1*{,<5f&[eݝ5!Ӿ;os0g<9ZLᐒ0e7R%&f>ĝot:p:m=|s{ âI&Ui1O__Sfp ;cP;w[1Ȭ ~K-. IDATjڪ7*uܨe@x^+YkVF/:/}A:g.N.zn& =UŢ^PӪԀ\ 6{֛- ;?{ed.wMFq/Na`/:D*|4KsfJЂ{6FnMLdBm] AY:&5O6~ͫ7ܹj=[P Y;+wSZN-GatE~R=!B@lX%ujCN>@!C&+j5/!a-Eʅ۳Q ,%`[g)յd=c>M{^ŀ[jG 5ۣR̉&PrRȎ-\BTTlT Tț]dWsx<|8ڌS"KG~Oܸy''\ qJy),,,Vo7rkw:\<^\☓S]ڊ:Ɩwd?y{_$~ Йn5MQ(3@ŕ)IIr3T>eAfT".5vڝue̊WZLZk] H {I>@ x,5v_SHga DW(o,fʘLSfrg׭#tҰ5F`ʣ|W̯EݔX?zeQFY4i2?fu>yr{8xdxGBY2Eh0;^Ebv;}dIqwuZkNmmM"?UaR9xYJKBMde+ߎ/rf.MO]->5 `IrQbzݲU.8Id>g3zvBzj>TzL˾$cgCoMw H ,~&tʲ696sҶkn5;ʞDXw\,֨adGZ Z8']:u{Ѵr&3tkc}yGF81&)wLD,9սm!Gzi]6zvp\lsNmFO\P/J'cfv .¿@n{×^Y7-6l-M,±OGh1 "RVP<DI=+-Ruz3N@ŰY,b&olMNn1,ȮWf/@A~T$GrA5v Ab2֚Š$T4ӪVo,N/9a3dw^e\([0CDYSƺ# U2Lg_PNۺi"@"d}#gl`a qr2K2yRa)˭!sw/&3YNyZJ2ս߈`.]l܊>? /^gX̩5󲟡Q%8𭘽Lǝ+5fpdY un;VS,{GX #p@D@g0Qvԍ,seT=~f&HtI[^׷]3i0oUh1US>)ns3¦xpg~{'ڪ0󳧾2^m rlj Muù*(Zq1,0J@Ɛ̆ٱD6%(|ow whq) 4B˄LL\ b?^Rsv COY#3ׁF03vl;6Q39Hnl D )RDRʶ-ضeۖi;rli~c-ilZ; ;q&/d{tjLp֑ԕ7aDa)4=; 2IkCq_8|スkV|2pSB~v;tBPVL;3ߏn\BWx O?0A F  LasRCR: d||OŲ5"0IQeBE2" 8DOcKT\$Nղx%%p$@na&}o8ᓧN6#"֑@,K)l˲m˶Ƕ۶[-PqjVZ-mY[ͶeR3+7 bZ9ߌb1Ge+HR.U]bTm;Hu '[6ڌ]/ 0PZMs{d|' "0&TUdY T ]iRYi#r@"C"X81 Ȱ clH)"f|W 3V%# F  H>KD$ei"& MSD]* f.lӎ}Ck `vM6a(RJEDVD Beف*ˎD)(KJE!qEB4 +XDEֆȲ,6h"$⣗,j>aAۆH|O-EA J%F 6/cY:hO>̙rzLl #YDk bf7fkƌWȈƾqPbD1DBAŀIR21Fнw8;$nvmQHZ-COiX, g"&!NQѴ-U6 NS 3n "&"U5$,kN$3Eh eJ!`0 [Wdkvѥ! dLchN&ȲtIXb*1bEϡ&|F(2Fkff#2E]r dv !Dd┵ D$$R^h$h2PƐk'o$k͊я1@bq$sLHi{[(]l ҷ>I , ,5|LTH0KSv@rPȲT(0kY#[s492hE+#0l+\oM"`h"LwžȝK+-.J!:B dRмnk׽BU=I3,i 6VBhAdI&۳=2VK%7}E FD"X DHCF 04X@ 5DL!fZhv]۞fi)BD,X ă'IjJ"a(b0T&<{˦4ׁh [,1k*IJw de"AqF4Y$g^{jǧ)JɜRAjdbURI^J ym2ŬSˎ4Ä2?'lI`0ða EXI`DN]LӅ#ð bKÈ' ><@"xݮXTb6=P1ģ{ }4RF*d]a<BӰH柛 %",A2JnSw~3郳SR1fKG(RAd6/P-+s$d ڈDLu h2_Y]/ c;6:bdL#B !|\\@<9@6bl*ƓX.T.Px,q`>(hg3I45ߨLHSDY҇TxR:ۥ5J@m{$UkSIyJMX2'-)*A q~[)TV'J> 4"hDiHf k 6Qs(eS-W2W߿SyQQ -8AM26C8PdEz{9fPĂm:>8ن*6Od rը^&jq=ai.KRfˢTAFmDsEaHJ!TGifI,7h_"-!E8B9X(+H;6Y($Nc.n7y I̭IC*h2^nTFTY;Zk0 +YB<3MN5Gj"Ʋ -xkvEG۝׍T. 3X U:R2TaJ%-\rm&d¤YY?1R2 NPV.FV2" f#qk$-$셣wɘl7 [299GEJU#" %W @6yVZ39+VU" %ݬ+S(EbAkcaHK- 1wpﻑ~ig>3aOU>:wOoQ2;ɗa/ID9X-P5$ vI9Q?ٵC]=RC-x /0 1{uqgh3P.f6 +fM0 &H$(I&Q3lDà]ֹJ({1lBL, b-"5N)f'UN"ۜ쓚n}8iTs %+ Nw&fE&ܧY*w:78d +]xB(ʧwvjfFRޘ4|# uq1 Pi`)o |,w`�W$gK01ᤁM-ֹ|)eRJn>8ZK"EgB^I_#_GT2seQRlMeI\r 4:S' .9ħ i\4RͫkN>d.$)ḋAT&H2@RטԞ*(J.1_ R֌~ޙ 8>ղHK <qA40`Bžr1`+uYWM2'Y)ɶG;;7?p >ְkq`"F8{a/v"6na7J"F崪ްhVTrLFۜR)hn %QѴfc&/LuT'E,*10^D) YB)L6p XmDFX4 %"  &L3M. ]J2aoMvvk w'ދ}+O?vZBmzހeR`&~O^oWo+; 8`CL&j@,&]ϔE@i4U塙,M\WwhEKӾĦiQK&t)c3Ś~ӟ=sf? 54)!4 I+f*c3TCV<,u4K?Ǜ+!ݸ)0IRϭԜFSoًo?q25`3jXvb ;JUVr2&h8Kj{78 ByMn_ Sȳ$dz*ih#I# ,T¡@Ƶ(~G ݖ &&' QԘ.H:j ,!e3umsY~RNݿfK9'<_O~ OP V"ؔ],˂CO;?'򏠵AY4.G10̳pfԴ@`z)a7\eZ`JK3'NRI2gsM#i0YZ8"a ))JU⯬/$G?8{& ,DX& ZqL\ NB T:ᦙiVB\ ||Gr)dÒKq#r a IDAT~ǿ|Os 'A@2 6"]V]/!hYD b@QV kSyCXZ,wp)۸r@b\rV2 8TJ\|#0HLE`&,&Z]j*-7zctz R'D :C wPt cPt> ril Q}y" GD |;-zd7uj2e~xGD}26誁&*g_Z;"+DL% ]8*N6O=A}LN\ry;["˼ ff-:0^$ D>ĕ(xc&Cpqrd~MCk3*f;U½Mg  KaᒘY~bvh @V 2=wUSbKR±8^F0A@pCl<' @%ҟKUL) nCU#[EmqvTRl"(hӦsvbZ-d#, 0aqm²{ -PDSX}LȀ)åk4&0멳 #ĸNً_|g{e4 dAi%("X@bAdZ4dVN; s}&beLR[MEkwp?W_h+l͈A/ç>'΁KYu!qsM=Gψ%U d(()뙅ED4{cWej@fy"RHfX̴2G ' qZB1A:a|$bĸ: .~P`ƝUL :DbJZEmYDԊ^M3j%"= iZYfV쇓9-FWǹ :R`=ٕ[|_Guەpw//&@*fjaeG0#qgLE);LO~QEz-O{YiP # 0AĂ }ȅhl< boVv+;x׶;u1${a l"ĠB,1W\fesp/\/?_/v9f/!2lfgU1'aejh~nsF''jP:U'ciشyE[Jɘ|@Iz`f Sd4XUhqRLЈe: isM) pj/)?|1(v!ƫ(YL?jK&hvm ų#!XF !A0 "t)ʑCyO?>e} ^~N[DBq TeѳP)Z`Wrw 6vXʢ̍HA 5ٖ5J "f e'0*$F&Pbul,c=mOnfN}pIN}{#kCIF &0Q*E0QB 'Qb ʬj)}1n$-eu\ ` 1XF "#\|bf&"/6k .',1ǟ~-_9Ŀz^r^RLvvg3oD[?@% ,#wYXVpksaZn/hp=HQF̝h[,uC5\$j'Y]"VmkamC&N_G!8$+}SկdP>Pgo)tspݏq(d Q-UM цB BvXdæ@.oC,m;x߃OiO?26ɝvG("dXYȌ|k-i:Φ+ f2$Tlw&JwMr-ڭ8/, H\fbQ!l5D%1L5oxrKdH+F#6tGYǣ]XuZ X/7F[/^|u 58a8umq\G}]4/K^CnвXaИ ]u Hp@H(Q͏d#֩w{Aiρ _DH'LHApPę Gk7eY9`)"Tf#$kD HT:~~sǠmỿ o~O?r`[/p xH]u].e&?wkV.(cWksÍr;_OݲJ3z׏sEL&R̓zxN]Emͭk+w:ulM=]w|~=s셯:7^za2LiPhlq'.F .XutdĚ[ݥeTmrRٞ6rc+7֒MUĝ,LVR˚75ZUH=a(7)fk(4TR`6ZWL۶,~Gus'1 vFn& Tq]yhWx c FRlyyCh9j!;FrPƏ~A#plp}GG|텯_g_}YJecPmL{{?%2xႴ?nHHO$:tABI-(8`~3iN2#Q Ym^X"ةk<{dt!LLX2:I`r|њxMq.V.M:E`)Lm@9'>czڙ`qunA[|#g_ [x{Z:D{lƒ O5?90=w'~#ɏ לFXkg|-37g>3DDLhRz,ۆ14B(İ{ʨ|_ZlH>cc+Pin'jӃ0:f$I,AaŝqFe&nN?r3kCr1;'fɌ7&e2=;#>Sp)fdD |/ȷ$ S.eƣ~WXτLUŊO?|r<qh9g˺ܕ]/b8w;Eư!ʄb)Pw*dbxdkOͱj$w`y\AY0I.€ !25%DA*/šL&~dOw܇<#x[d~&[O M~yt4ۗݏ¿I/3͋2;Yw=N+/߀ysQ {T,#?1?OO[j-}LM&m؊|8p@II`bM#{Pټelc̀$/Z;U5x ^ugL|%ˉUꍒ"pW<$N]8Lo># S|~^<%Ƙ=& g_pfbTQl̜ M<:ߏ=p-)S鹗oT'Y.eB>i}eY֏؏}ϫO^"hfafSs`r 2*1 "0y,2 AF$2-,ĊNbDYN-FVBժ_&0t|G\eJ᭄ $u!ΔġTr] 5>&rfH{{fkiLkֹzkmxֺtZ~p4k%u&s}n6)-RhI!#645LH燍g06&?? `8$$ `[v4h,aӢ(oR$`UZUΫE5[@yݮS眪ZߗE) )d~ cc_ 0HNY͐Yee0vCуcӰlvxk5InsM)޴kfin/<$Ѫ5N51+)ΫN&XH RE}aI1ρT 8 $h$3y6zؑ RzdT}Q"X<&ݨ" ?SQr90K0('&uqB./7(f-"XՍMdZT)ZF/Cs^(1Ҍ9si篮?Ղ Q @{$?v/4pWA}r @^7=fF?5xKWܸq5 i=zY|ıIQɓ'_c/ີQxz,Fmn<14(HQ_H%iIV H M`$Pu$HQ™b-dߖ-IT.doN,Q#4ιw)lHUk^iv}?9pKC5 3h ֍GDHP^_řKc |sG~<9wt8zp{SDyɵ އq`~GML}[=.g6ؾ7b ;_3&Q_~_< A'HA:UYq#@م[L,ZnPH_ljKj `? %:?ZYG49 ņ2 W]y{&%!G*5Q7F a?UX s∻P^ x^FY&!ה<0ṭN}?| .}-^?k^@?K pu kC:=XKI"_9e$ZMLG6;}e%*"I X^hNŭlnͷ7oܴb g1=a3IϜ=_=zdq#G<~رϟ .w4lW*|o鉕mF;QUE2:!HCp}4PuWm0tnq9\J4AEN@e=jETp.>po:{bə9Q)R;<9ӯ[+H3E+E1S*}t4΂K7q*w:o'8+Wc0A8Gci#(7$#8IK$jL_Wњ;Ϝ: FMǧ]j'}ǝ2^~'#7y*#ũC?zqg} g28:2V d_^ϲ'mĉ\\!p6j LKT:)ci%(UДQBp$hH 4/BrA>0Boi]$8^CVקI:(UʭY앻fc`OjR}V1g e|u& hi@۹8 aH{ָqids4ϸ?`cc8ٖ4qD||T@cRB[aOd$s?\/MnZĽ+/qn;pCEBwVX~|5i7/,28cL9h`-$4=#\:5 t(eN_ LD!dG4,`ԉBWgNti 0V[n4X #VE0Qr\O4iW[U{6¼Sh-"+e_$"QM:GHRø|mַq`9?db6XǬltk>{w-`=]UM-lNE06 q H?ϴw՘=v޽1 [> 2;TpSb C+"K2W$Αҷ  $PU'B4R 4)H4}gEĨ0?.BUhʿ+TkDeȐw-h@Q"78b*YqbΉ PAėw*_Y= #G`Y(HELM_zLx"|C_˞]ZMEڿ[O7L`{?"c5)/xLשhI}QxP<O~!*F箮N= u'GcBF@xh6X:;e"I$DOM1q޲fA,#']hvs"GǦOH&R$'4H R7ő̸F+UOjIM$QT2g:Ͱ6U"RϜ<>LC{F xtu5ؐ(|qRy$e ШpcS.pϘK,X+Qg3*EDM( 8#蟢l.90S c5D>塃nXD4F| <@n1Nđx/dӥK4U^=rYQ]ҳ (C:µ8we>4[y Tw%KS=%h@̃X|>g?wpIj6?K%ڔdN`#h!EU_Ƨ`RPE$T!]1I/w*ps>\sW7rO<0^x8މs߇RZ$a|{sI>1ܼUDYcx^cK$cJ&lҢCp;܇N-c$),qDƷax` *:,6K,}1L$x. - g6)Iu}n4W32n$/?h$i,lHJֵZ4Sj ;vܮz纮xtWb686̌'y:v_’f?|HE3ZR·EDEؒe5۝L2zFYlpn0ZPL}f1vh%FD, ʫI'f[c""m3@޻N/|sr?Y&*(ݙU+ַ'eJl׃JM.TG7bf߷oGS><2Bza:wӸh囸qkM|w?9rK rMbO#fY-~k-;ȡ椈ԩ'P";eQW7A$g)C52pxBd0^|L \4xƮ#5*W`,a6,oC _$eS̉,dmXNJ=a߾>v?' +2:ѭU+/jl2>*ׁo]Z?>2*8wec,p<x3jMgNdH4d%,cY=pZN߷oBlջ1l1;BO= V&.fdƥṔEf-l J?!54xƮ+b2^51.o6,wmSylA)5}l=05'rAW+5 TĦT#qIJ(R1>Vx>6ICff7nc9<}R}F " V"'f`kY&óٍ2o6vLړEn a `G7AM u_.͒6 -ox}xՍXLP - Q,"LXw 56"aKM%Mz:~nZk|~W௿rmluWԀ޴0/2ց FOFNڟ(e¥[G?@{5v><VV=Xq^'t s1)I/]~tfC'?o.]ԍ8w $a5zRu Gj"Idd4Yt3n")2!l0v ]-d"W`dM o0w`,u6Q:oش ,,|9/ކ,-W[\h HN–#ph|Lk+ӦɿlR^rknn;<. Wq"FV+$k! L8 i Nb׶|[>X0`(Ӟ^tt9~8q` _;~moT45_FE4^n0 t`HsL3AʂSs)L&ˠْZHEZ’iC^x } G&]+8C?aeU5ZD'Ax'OũKШ\:)SI䄪Ɲ NՔgxI"4lNpy6;gv6xͷԾط8iСCɟvވ%W胈K_ҁ|+Ϟ8qVgqqGG׈JSZIE3Sb@f\ũ1hjR@D4w ZHi)6LL,F4@EhnX[, j AϪ7hTLx |祷G0DBD,?_Q94ɷZ=IeI{.շ4:/Ƶm;;sIoȧI| eg"؁#ܲ+?|WOXjr8Q*6&;?ɔd=Cc(!\`5[x##"&G)Ҥ>E}vl.\wn?gFػwᄑ{I{cћLUV@p_nAIa8]vmv]2^CfWpK -I g"Ƭ5bӁM{6)r@P߽&˿=-Yfg6djssUoasS—,7;OQƞ(vJL.][c ׺zCn 넽^p 8ALl.;d?g^xᅗo߾v7;߶Z~w~˨/4]Iul &c4x #QFY2(fDL@AYHFm&XjQؙɱ1AH}oov/ݹQDAjw.Wëo|~W(gݛhfL#`Wtq:?k}`f+o0 8[Kd+}hξzۿכͦy~qL[9u?pz•Bj=j2cq:^ 2 3*Ð@9bdcz・ ~iu\E; [ng}O "b=<#H#p"M_x{{=3O?~}" "".9s[7{ʕ ;F56?M 3ɠ-SXftL dH# )DeD A@A +4-m&FSsv9XJIerwA5z*Y"JE(6)=U]T#F %lQS: {0{ط KX^lcB#PJ2 c-bv>Vֶq}e7׶p:noHSV˲X'M@9Ǐ#(7M6tx뽳.vR-m&\z@| :]%x8%?b`mB MY TS?㕠P%cVV|c\V\ Ȃ^8,\\ wys)t=lA8gB&%`n߾}zc=ܽ{ťVnZM&"%"b̜fYKӴַV.^{?~oj 'ժR܈w jʛj`2〦*#X6j,ZH &\(YJ ,%Rz@z96A jE$b(QbIX^lBssM$:iKj,vo^N?Cq2c+v [@ث4ݭNP݁L8#;DQD(<؁@/g(W`hāZ# {? &DL*}b"f@`|3qY= @J H߃߲/q$F #1>h]߿k޽sfSM,tF͘s[0=瘪#SL)qSlHU|Y&"}a&հ"ƀDl HI@ ITNzPOB-0PK @K`RȰ66;N$$g4K:B%%|?a= TT%#{/*C=L# M.XEG.J^\\,ll\I3(G5bʶiG0=:)R>I 2,"a766z9bXJ}˴gheFf  '11`BeH&–m|8٢0%)$:.ܹBE#5iQ|RD0`v%Uϧc*UJ #6x-YH({R3)4@Z'y~{**!)},y"*XJ &p &"P8}HfŦx``Flj glO@#y@}Ũݐ!UDbXNW0y U[) /S6fт)%SǟP HH5 Xkf` [ J:D${@QI3~!M%#KI0Iz*PbF6YJ"7'=yZ V9АyJFJ> H0X #Hfi;Ħl? 8MsY:wM1k8d"L*յSoTTrUao:}+GM$$KN#S27m_`[ 2Lb-JTO u H-B#&-BEAy^yPr]F$) 6Ů@R:.ކx!`$FE請-#)5eג%ArvH6ҙ oEsXX@Drdui g6u)[+ lfu2D(R R.cy˘oYe2st΅/D"=7b, YO92בMPPM\'U )uz+U!j]&1M76qM \ubU.Fv@f|c(fTp հBƒjXր(HLJ MzPKVutWH-<h jjB-Ԁ8攈}5Rh ]!Ձ^ BjhhՆjG BrHlOF)q8;Cg!D# Dz KqQuݒTD!psqcAe# u8ak l%eqU!Sq"R'+ y.dY%ڋ렦l+'{# [V+@Jk"DjKUUœ2?FQJ||y j{5tt &|5&hF ]H+(.r PDJQqK9I\ah=`\]r,&dI44}]U8q"X"G:5ҞMO\`)%LN{@ }/+ a0X-Ǣmt+iRHJ\jPЮ&صo{"'JThC4ChDŽ!+< v.U14hƂCb#fuCfBJdݼRjOH/QZoF@RjL':VMF](Ghr-p03C}c4Q.H'PH -b9j P%/BAg: : KT0)ƥRy7DQqŭF3DE%"+ zX憘gRsD^+ق6K3"r1m1ܡ;{1'̐OZ'<&i"x`v@D5quvU{tOgJcP J74rB8(J)E#"U'<I^*}"ck"]59) ݊%lS$tZuN`&K>%DYMRWMƐfLK~.8Vg_4Nfd} U m9SIP ItъjkF}_OB u9|hC\"yn1 HdDQ'A*n|cixDP|D8c.QCqBz0&½@;U.Ks*IeKaK`bAΒC"hsƭRMe"3&JƇc=5}7'4B3Ӥ<3 ?O7 DQjuE@4@H3`MP ?7PD2^H9'%X.8yDT;IB&r.ݴRD*y b&nt?( Yrк(~FS̝,w隷23?$R7tMT`.Zi%T؎AƁ.G2C`ERad$3KwSӞAWmʼn} #Ţl&%nD O {Ӿ.w6; IB}gU. <J%E)Dr@hR:! D4yf PRCN'#q?)#k0l$LS ) /UYٱ2& Cĸ9,?dg@3+،:u$W-;EKHH dKN4@7NԺuE"v Ir'Y>> TjcF2օ)u1)lTiH 4Tߣ!mԜ'l&E8jDfpQchaȌndVZ.; I9iUI'ѴQx㚿iujFO Oy )';58㢏YDFU˦9~FҒq`su2jĂ͸fLc"4/'r<^G%J )0̧&8sjJa)"qewrR5hD; 3`/2M3) L 4r510&NԲ2;`3p0%`F0 9n?' Msӂor3>Mxm;]1$4 X ,;2;ό4ʹ B43CJm;2;]V]l^L r,; #йS .*; |̿#NJ| wXv@fgX,; ;s,;,;β,;β,;β,;,?czf@IENDB`Grive-grive-93d696a/icon/32x32/000077500000000000000000000000001177605442600157745ustar00rootroot00000000000000Grive-grive-93d696a/icon/32x32/32x32.png000066400000000000000000000044631177605442600172720ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME7d<tEXtCommentCreated with GIMPWIDATXWil\WΛ7xMıbܬIF jj ?XZ*jY~*I X*iiE%G[(H@*$I:v;x<彻sᱛ)M/ttwws9O{{qUz?z7.MdBLq6Q.GR9Ŋ>:ʏ>JlWӯˇgΟ r}Co*,w%0pIr쩨!o:nW`ço|EX+ ^]Z[,P#m!:T8ɾ'M#nzʖYj860ցCD AהPt߹Dw0j!2v%p: << DD (>c97>|t gyXkib1S9FbEIP(44xľxw}XXDqA+K :fBU! wc4MDyGzXc`SobZ[ D+TUADHK'KftgFDITT "Lm.6zEU "`ᜃXV"gǢ 'Gg yr , :cMR[$/ `VyO03 "5Q@;91 غsj^%wBJ!`fR%\'-<YQ/ B2t-0om/0HUU@Y!,P'/8`|~}C2p@@<M6l^Lh@Fk3wU%R\VMgrp R#"T!j(DII z;HHq1k-vtbѹ %Y;6r = xξoaK0#ڜ[SEimC7H0=3#HPDWJF6[-}K DT3tS4揯gb2;e*ZSXۋ'LNDP@i."j{)8x,TA@qgf/j ch+M>䲯 = %Fd( 'ƵO~IЇvcuӋ!6g( ˜(bI!H$0ND`V6/O|aG .&SDA j >0N?;nذgμ5˱oS!:RH!va,d}*HډdDz'm %y@fNꞀ &\܁cO >i֍o~zlbl[ۈ{֣ Sy] nԌ}nMw]SwY^S\OMY=_ *1u2 =i߃6[vb^F#EAiDYR 4 p! H?0˚ꃩ* McZ fNu:uT ;5 tui52@XO՘Q&ѝ7cpuɝ>KUfkacwJ0=rfx.LS<[~F$M#s4]b4`d<&( O BnfzǃD`{{(xdd\.7`JZz6p в,L515$!&{ V&Y-Jpb1+ iԵvQ^0C.  Rʌ|eZ _d'QWg4Z 9jO 6IENDB`Grive-grive-93d696a/icon/48x48/000077500000000000000000000000001177605442600160125ustar00rootroot00000000000000Grive-grive-93d696a/icon/48x48/48x48.png000066400000000000000000000101321177605442600173140ustar00rootroot00000000000000PNG  IHDR00WsRGBbKGD pHYs  tIME6 { tEXtCommentCreated with GIMPWIDAThZi\u}ghH$" b)b bW8S;)\eTR ĉ)BpR8c# I@a}zzz{˽x[3D('=u5SݣwwׇB2U(KjP*URJaa 6q%6AdCH>tTnJq_^_%RR*j:CQFfVk3jD<\Q>ؼ_z?< $X!vgعcBR^6}{NydN)(b+z3\Zv;^ϧw`pbzϰ "ϕ<DRtr"qPэѻ[6:Fk(tGiqRc,  " A('Ls͡ "V~DoVV (Q!cXZ 9 V3N,DHP4ol]շ\hpr!g03,31Z#1Qa"JFZ0[*@DH>E{ `5Mfυ -Mh5(#.pu88,ò[[׫R >55KZ 'Y=!Wca15'T*G15NW̮|F(Smҹg?<5kz̾WC×vX֪v;7hG}"AA.> |F3</TP"yk ,"Ykm'",v ޹amzjDr2* |Ū5۶uoԱzᘥYMfʳ7CH,d Ljk+EI:o;`y6dyQG$B`K8x݊E:e< To,˔dBXo]LBcB7s2G3/!!7LoLR@*fIh'nrփpR)5:fgz 8`d:w ,%L#SpIUg= ߩ `f96@j|gfgĒjxoMf5֊=<=0 葯Yʀ)>x/uKx#@fo @ѻȷwuNw!r"50nYemeo'vV ג/H&,2ٮ ޻}Նm1­dHRD@V/i]uGʳ8ɖ aQ p8fHZipѽ6軭`ZA-{{qٟ?Ъi 2j<_.F!2L,[yוي$䂮yG)xQ( VaM<8U |ZL“Z7Iy_ASRFD$!k2MqWli㲻ۮ$_ "0 B I{jsB1֔'m/^0~d4â,l'Kk9Ib'ڸ-]f! mHʤX݆|%O  % Ch K#Νizx6x@Bl"^g &+Opw~Z@uJhxД13=L^8sH4|W`~g!'j6El~Ia2153 >M /N6w\W_ Dh!"ɦgv5￈Gat8ۛ q4>V,nog,IJ6ne Vt0=5 ]Ǘ7kH<5>|ڍs.yu(hdAQ'IRD? Kq]czzP* DPTJhOn7K.pW_ǒfⵋsI2裏^jժ 6w6ݼS!t,5B ])c"gA ] 8! T*  Kgi@d 8aCU<3,b2_C $ֆ.Z_wR"BTJ7' `dYI܆lj/ٲ^`4Gft_  !8DŀRt3( c8N*>/<]݇A QR*-3>yM'+J{}.dԨ >nf`G:Z'8Z}tіLZP 4IN0Gbxnaӯ^3]n{\sY+cccQֽή{=b2@v}R׺z?u>vM‚,^?8')f=AW"SŘNJXb/,IENDB`Grive-grive-93d696a/icon/64x64/000077500000000000000000000000001177605442600160065ustar00rootroot00000000000000Grive-grive-93d696a/icon/64x64/64x64.png000066400000000000000000000146061177605442600173160ustar00rootroot00000000000000PNG  IHDR@@iqsRGBbKGD pHYs  tIME5 '#tEXtCommentCreated with GIMPWIDATx{i\uw{_wl` HAp](.-lKRb3E,We#TeRG2U$JJ%Sq`frg@R HII%]u{zz9;ι~_M'^m(vvDa脑qp+(#iT lZOj JIT=;[إKtL0h nAV0*aGqƉR&*eKRc2(z+`L3R,>fJ8 wp~П?-nIaEE1IIT2I(RTfNJ=+IL5b8W"#Wh(we;X7Bܝqƻ/#w9.%RB[XcT s0"0&IiE`hF ,Ԣ\\)=[k5,d(00XȈ0]Z+j @AF5S:%2KˇTd R}ɞ<3cʼnɸ: |jMJ\18FE&HL$LHI!8b6 Xg|V%hCkwxlPRۮ7wX|=he2g$hLN؟YjE}Mwv:Zwinu9.(K'OO xJQpaphV}Xk+tidL:q);ϑ"%ѱO/}xr@(ȑ?rFAcpkӀ{U+i-;D6)%s@SA;h VotR'jy~U~B5 3R5q EO)hŸ+B}ZjucQ*RLTK %Erf~^IRxCXǭ'@7 Ji6 6w{l\ 6ۆ>t/_IYM!5_8yN%854X>{agf-:cV})r) =+& U['"Ov)ѥz mn^>@k4K% \NZ `4ٓ—,߻/wuݩG0q @R`jҟF*.OͰ~fp߾:aېu,Kzej[)zBLv {Df LD͔Lܫr{-(%wt+u(X :0-7j6S,Ĺx-`eƯz҂($oߣ_) m;`zuуȉhc}wk10m˖^}+[ͳ//ͮb.SVc^q\9 敃{ r#+?hћMpg~@z.e_xt^@!Gh1X VWܟ*S c?!Ziɣ< ܸ]Ng+MpnfeVN3(Y4]1ưa d+J5|@m]_L3($Ǝrܕ~`]w&bn)`9W?Z ٔma5#&+Fy2vFX܍ rɁ[`r~8N L2(7bt9H kxJ?'|\:d,q @`C`1f"{da%Zj?ks O>=1R#~ M M7 +$}CIn;[:-fmtIF&HMqW0 9DpQ;yX'Y˙qOqx?K3H0E]`pFe9\7H+ ?ؔ d7h(fRZ7}`! Ӌ3.8"[LmS=dé,k^Yh,:9?wK͢M/ J##=viB~ %k[5( ə$m9΂ߥ ";!%]ߦn(XgƷEIU^",aB GCLEuKzӶ&WЧ60DB ]釳jU)mpپͰ]Z!0v8ug~wMP>AuŒ_I V;5MPVq t & 4kW)meXnf%Am%tPY jl,\\܃?@5`c1f@(Z`_;E6x k4 9j\m LfLp 1UFz` QQvp< V+qD%I7$ =3i0@8T]c +6ySi-=So!a0c8Auaf^c'P-Sp&ib/3=@klM'a 9@FFh9> vu[m< dh9l7h!T0DU9\tujBS=ʠ5\.vh* 9wy2H9aCCQH(,ڳ*'_C=3SH a]|)ȪCDĒӺxQm]JTA@ںFAo@ 3uzgE݊ޏcx SʷNϼ6Aa2LfU` PrSgsP6 cl-"/zɒr` %!J GQ/0et4p`W?e'N_ ɧJi_KXY^5{n1TջQܽm[n}_7J d}C$6^fC*La( ZVD?H8 j%<MAf;D5!T G?s zKlwq%\M>; :K ?Z>]{СCFGG1C( a?;Tdg4%c4Xko'4 | #"H>9&)`Hn&fk1ۮߌcgk*=~vcc縿sSg#9dSa=݅Ba`dd1< L## zM~W ؚ!DCL'm(VX!cs?*eEW:V 8BJ!鵐("a$RBk 0^xvm-w380 3ڝyDѽ} t]NV!6n`֔ҌlzN QpEBQۅTV? | ر?8tv Pq2a$ @T6%%iw| ~yxl-<ܠѱrPq&ҲmeBv0Uk)(.j\Wm5jm佻d N@{.& J|@ %-0` ̯{6o-tzb&j5:{ĉƓO>9n;гe [SK:K= 5IJopMy[/_tiO/(r?lĆ^H XhMQ`a i}pxوn?@I)4>4;y~ww}rR޳gu _2+_aЪ!V'9IBQt|?~ң$ۆ\ +x4v{뺺X,q|ѣ_:IWsJ)X6)*-!qad(q['' g'.RUY|陗 jxEsN3@~?+#N]DZq_!#JD^N qZ''׎U{*ۭ .nZkh,OLLs}cll. sWsb+^7Ww+d/r @ZJibc@ ! NjAp M  I -#WaH0"YD&XP2l`= qS`ep\3,EF6VM\Eڄ "I( @?mZVh4No6|-oWMni?wS[[,[.=Olt:"`bN8iD͐ejTk.ժVܺe^{ẔʏKL9P * onq+Vr)nz@`TVI EUЂI&bZ87A5Hkk\vѻy/QQN? e|0< _Ӓ:شFU_=CVi89"s߮]uEI:v%]M̻rO9!:xukP}w<Fc7SoS׃C0HM+IENDB`Grive-grive-93d696a/libgrive/000077500000000000000000000000001177605442600160665ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/CMakeLists.txt000066400000000000000000000055331177605442600206340ustar00rootroot00000000000000project(libgrive) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") find_package(LibGcrypt REQUIRED) find_package(JSONC REQUIRED) find_package(CURL REQUIRED) find_package(EXPAT REQUIRED) find_package(Boost 1.40.0 COMPONENTS filesystem system REQUIRED) find_package(BFD) find_package(CppUnit) find_package(Iberty) find_package(ZLIB) # additional headers if build unit tests IF ( CPPUNIT_FOUND ) set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} ) ENDIF ( CPPUNIT_FOUND ) # build bfd classes if libbfd is found if ( BFD_FOUND ) set( OPT_LIBS ${DL_LIBRARY} ${BFD_LIBRARY} ) file( GLOB OPT_SRC src/bfd/*.cc ) add_definitions( -DHAVE_BFD ) endif ( BFD_FOUND ) if ( IBERTY_FOUND ) set( OPT_LIBS ${OPT_LIBS} ${IBERTY_LIBRARY} ) endif ( IBERTY_FOUND ) if ( ZLIB_FOUND ) set( OPT_LIBS ${OPT_LIBS} ${ZLIB_LIBRARIES} ) endif ( ZLIB_FOUND ) include_directories( ${libgrive_SOURCE_DIR}/src ${libgrive_SOURCE_DIR}/test ${GDBM_INCLUDE_DIR} ${OPT_INCS} ) file(GLOB DRIVE_HEADERS ${libgrive_SOURCE_DIR}/src/drive/*.hh ) file (GLOB PROTOCOL_HEADERS ${libgrive_SOURCE_DIR}/src/protocol/*.hh ) file (GLOB UTIL_HEADERS ${libgrive_SOURCE_DIR}/src/util/*.hh ) file (GLOB XML_HEADERS ${libgrive_SOURCE_DIR}/src/xml/*.hh ) file (GLOB LIBGRIVE_SRC src/drive/*.cc src/http/*.cc src/protocol/*.cc src/util/*.cc src/util/log/*.cc src/xml/*.cc ) add_definitions( -DVERSION="${GRIVE_VERSION}" -DTEST_DATA="${libgrive_SOURCE_DIR}/test/data/" -DSRC_DIR="${libgrive_SOURCE_DIR}/src" ) #add_library( grive SHARED ${LIBGRIVE_SRC} ${OPT_SRC} ) add_library( grive STATIC ${LIBGRIVE_SRC} ${OPT_SRC} ) target_link_libraries( grive ${CURL_LIBRARIES} ${JSONC_LIBRARY} ${LIBGCRYPT_LIBRARIES} ${GDBM_LIBRARIES} ${Boost_LIBRARIES} ${IBERTY_LIBRARY} ${EXPAT_LIBRARY} ${OPT_LIBS} ) #set_target_properties(grive PROPERTIES # SOVERSION 0 VERSION ${GRIVE_VERSION} #) #set_target_properties(grive grive-static PROPERTIES OUTPUT_NAME grive) if ( LIB_INSTALL_DIR ) else() set ( LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib ) endif() # don't install libgrive for now #install(TARGETS grive LIBRARY DESTINATION ${LIB_INSTALL_DIR} ) #install(TARGETS grive ARCHIVE DESTINATION ${LIB_INSTALL_DIR} ) #install(FILES ${DRIVE_HEADERS} DESTINATION include/grive/drive) #install(FILES ${PROTOCOL_HEADERS} DESTINATION include/grive/protocol) #install(FILES ${UTIL_HEADERS} DESTINATION include/grive/util) #install(FILES ${XML_HEADERS} DESTINATION include/grive/xml) IF ( CPPUNIT_FOUND ) message("-- Building unitary tests along with the library and the binary") set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} ) # list of test source files here file(GLOB TEST_SRC test/drive/*.cc test/util/*.cc test/xml/*.cc ) add_executable( unittest test/UnitTest.cc ${TEST_SRC} ) target_link_libraries( unittest grive ${CPPUNIT_LIBRARY} ) ENDIF ( CPPUNIT_FOUND ) Grive-grive-93d696a/libgrive/src/000077500000000000000000000000001177605442600166555ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/src/bfd/000077500000000000000000000000001177605442600174105ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/src/bfd/Addr.hh000066400000000000000000000014521177605442600206050ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2006 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once namespace gr { typedef void* addr_t ; } Grive-grive-93d696a/libgrive/src/bfd/Backtrace.cc000066400000000000000000000040341177605442600215770ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Backtrace.hh" #include "SymbolInfo.hh" #include "util/CArray.hh" #include #include #include namespace gr { Backtrace::Backtrace( std::size_t skip ) : m_count( SymbolInfo::Instance()->Backtrace(m_stack, Count(m_stack) )), m_skip( std::min( skip, m_count ) ) { } Backtrace::Backtrace( const Backtrace& bt ) : m_count( bt.m_count ), m_skip( bt.m_skip ) { std::memcpy( m_stack, bt.m_stack, m_count * sizeof(m_stack[0]) ) ; } /*! \brief operator<< for printing backtraces \internal This function will call SymbolInfo::PrintTrace() to print out a backtrace to the stream. It will use the SymbolInfo::Instance() singleton to get the symbol information. \param os The output stream. \param b The backtrace information. \sa SymbolInfo::Backtrace(), SymbolInfo::Instance() */ std::ostream& operator<<( std::ostream& os, const gr::Backtrace& b ) { // the 1st function in the stack is SymbolInfo::Backtrace() // the 2nd one is the Backtrace() constructor // both are not interesting to user for ( std::size_t i = b.m_skip ; i < b.m_count ; i++ ) SymbolInfo::Instance()->PrintTrace( b.m_stack[i], os, i - b.m_skip ) ; return os ; } std::string Backtrace::ToString( ) const { std::ostringstream oss ; oss << *this ; return oss.str( ) ; } } // end of namespace Grive-grive-93d696a/libgrive/src/bfd/Backtrace.hh000066400000000000000000000026211177605442600216110ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Addr.hh" #include #include namespace gr { /// A shortcut to print out backtrace information /** \internal The sole reason for this class to exists is to provide the operator<< overload to allow: \code std::cout << Backtrace() << std::endl ; \endcode \sa SymbolInfo */ class Backtrace { public : explicit Backtrace( std::size_t skip = 2 ) ; Backtrace( const Backtrace& bt ) ; friend std::ostream& operator<<( std::ostream& os, const gr::Backtrace& bt ) ; std::string ToString( ) const ; private : addr_t m_stack[100] ; std::size_t m_count, m_skip ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/bfd/Debug.cc000066400000000000000000000032471177605442600207530ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2006 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Debug.hh" #include #ifdef __GNUC__ #include #endif #include #include #include namespace gr { std::string Demangle( const char *name ) { #ifdef __GNUC__ assert( name != 0 ) ; char *cname = abi::__cxa_demangle( name, 0, 0, 0 ) ; std::string result( name ) ; if ( cname != 0 ) { result = cname ; std::free( cname ) ; } return result ; #else return std::string( ) ; #endif } std::ostream& PrintHex( std::ostream& os, const void *buf, std::size_t size ) { const unsigned char *raw = static_cast( buf ) ; for ( std::size_t i = 0 ; i < size ; i++ ) { if ( i % 8 == 0 && i > 0 ) os << std::endl ; if ( i % 8 == 0 ) os << std::hex << std::setw(8) << std::setfill('0') << i << " " ; os << "0x" << std::hex << std::setw(2) << std::setfill('0') << (int)raw[i] << ", " ; } os << std::endl ; return os ; } } // end of namespace Grive-grive-93d696a/libgrive/src/bfd/Debug.hh000066400000000000000000000017321177605442600207620ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2006 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include namespace gr { std::string Demangle( const char *name ) ; std::ostream& PrintHex( std::ostream& os, const void *buf, std::size_t size ) ; } // end of namespace Grive-grive-93d696a/libgrive/src/bfd/SymbolInfo.cc000066400000000000000000000112161177605442600220010ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2006 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "SymbolInfo.hh" #include "Debug.hh" #include #include #include #include #include #include #include #include #include #include namespace gr { struct SymbolInfo::Impl { bfd *m_bfd ; asymbol **m_symbols ; long m_symbol_count ; } ; SymbolInfo::SymbolInfo( ) : m_impl( new Impl ) { m_impl->m_bfd = 0 ; m_impl->m_symbols = 0 ; m_impl->m_symbol_count = 0 ; bfd_init( ) ; // opening itself bfd *b = bfd_openr( "/proc/self/exe", 0 ) ; if ( b == NULL ) { std::cerr << "cannot open executable: " << bfd_errmsg( bfd_get_error() ) << std::endl ; return ; } if ( bfd_check_format( b, bfd_archive ) ) { bfd_close( b ) ; return ; } char **matching ; if ( !bfd_check_format_matches( b, bfd_object, &matching ) ) { std::cerr << "cannot read symbols from " << bfd_get_filename( b ) << ": " << bfd_errmsg( bfd_get_error() ) << std::endl ; if ( bfd_get_error( ) == bfd_error_file_ambiguously_recognized ) { std::cerr << bfd_get_filename( b ) << ": Matching formats: " ; for ( char **p = matching ; *p != 0 ; p++ ) std::cerr << " " << *p ; std::cerr << std::endl ; std::free( matching ) ; } bfd_close( b ) ; return ; } m_impl->m_bfd = b ; long storage_needed = bfd_get_symtab_upper_bound( m_impl->m_bfd ) ; m_impl->m_symbols = (asymbol**)std::malloc( storage_needed ) ; m_impl->m_symbol_count = bfd_canonicalize_symtab( b, m_impl->m_symbols ) ; } SymbolInfo::~SymbolInfo( ) { if ( m_impl->m_symbols != 0 ) std::free( m_impl->m_symbols ) ; } struct SymbolInfo::BacktraceInfo { const SymbolInfo *m_pthis ; void *m_addr ; const char *m_filename ; const char *m_func_name ; unsigned int m_lineno ; unsigned int m_is_found ; static void Callback( bfd *abfd, asection *section, void* addr ) ; } ; void SymbolInfo::BacktraceInfo::Callback( bfd *abfd, asection *section, void* data ) { BacktraceInfo *info = (BacktraceInfo *)data ; if ((section->flags & SEC_ALLOC) == 0) return ; bfd_vma vma = bfd_get_section_vma(abfd, section); unsigned long address = (unsigned long)(info->m_addr); if ( address < vma ) return; bfd_size_type size = bfd_section_size(abfd, section); if ( address > (vma + size)) return ; const SymbolInfo *pthis = info->m_pthis ; info->m_is_found = bfd_find_nearest_line( abfd, section, pthis->m_impl->m_symbols, address - vma, &info->m_filename, &info->m_func_name, &info->m_lineno ) ; } std::size_t SymbolInfo::Backtrace( void **stack, std::size_t count ) { std::size_t a = ::backtrace( stack, count ) ; return a ; } void SymbolInfo::PrintTrace( void *addr, std::ostream& os, std::size_t idx ) { BacktraceInfo btinfo = { this, addr, 0, 0, 0, false } ; Dl_info sym ; bfd_map_over_sections( m_impl->m_bfd, &SymbolInfo::BacktraceInfo::Callback, &btinfo ) ; if ( btinfo.m_is_found ) { std::string filename = ( btinfo.m_filename == 0 ? std::string() : btinfo.m_filename ) ; #ifdef SRC_DIR std::size_t pos = filename.find( SRC_DIR ) ; if ( pos != std::string::npos ) filename.erase( pos, std::strlen( SRC_DIR ) ) ; #endif os << "#" << idx << " " << addr << " " << filename << ":" << btinfo.m_lineno << " " << (btinfo.m_func_name != 0 ? Demangle(btinfo.m_func_name) : "" ) << std::endl ; } else if ( dladdr( addr, &sym ) ) os << "#" << idx << " " << addr << " " << sym.dli_fname << " " << (sym.dli_sname != 0 ? Demangle( sym.dli_sname ) : "" ) << std::endl ; } SymbolInfo* SymbolInfo::Instance( ) { static SymbolInfo sthis ; return &sthis ; } } // end of namespace Grive-grive-93d696a/libgrive/src/bfd/SymbolInfo.hh000066400000000000000000000033221177605442600220120ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2006 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Addr.hh" #include #include namespace gr { /// ource code symbolic information /** \internal This class represents symbolic information about the source code, e.g. function names and line numbers. It provides an interface to lookup these informations by address. */ class SymbolInfo { public : SymbolInfo( ) ; ~SymbolInfo( ) ; /*! \brief singleton function \internal Returns the SymbolInfo singleton. Normally only one object of SymbolInfo is enough for one application, so a singleton is enough. This function will create the SymbolInfo object in the first call. */ static SymbolInfo* Instance( ) ; std::size_t Backtrace( addr_t *stack, std::size_t count ) ; void PrintTrace( addr_t addr, std::ostream& os, std::size_t idx = 0 ) ; private : struct Impl ; const std::auto_ptr m_impl ; struct BacktraceInfo ; friend struct BacktraceInfo ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/drive/000077500000000000000000000000001177605442600177665ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/src/drive/CommonUri.cc000066400000000000000000000017461177605442600222150ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "CommonUri.hh" #include namespace gr { std::string ChangesFeed( int changestamp ) { boost::format feed( feed_changes + "?start-index=%1%" ) ; return changestamp > 0 ? (feed%changestamp).str() : feed_changes ; } }Grive-grive-93d696a/libgrive/src/drive/CommonUri.hh000066400000000000000000000024641177605442600222250ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include namespace gr { const std::string feed_base = "https://docs.google.com/feeds/default/private/full" ; const std::string feed_changes = "https://docs.google.com/feeds/default/private/changes" ; const std::string feed_metadata = "https://docs.google.com/feeds/metadata/default" ; const std::string root_href = "https://docs.google.com/feeds/default/private/full/folder%3Aroot" ; const std::string root_create = "https://docs.google.com/feeds/upload/create-session/default/private/full" ; std::string ChangesFeed( int changestamp ) ; } Grive-grive-93d696a/libgrive/src/drive/Drive.cc000066400000000000000000000121221177605442600213440ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Drive.hh" #include "CommonUri.hh" #include "Entry.hh" #include "Feed.hh" #include "http/CurlAgent.hh" #include "http/ResponseLog.hh" #include "http/XmlResponse.hh" #include "protocol/Json.hh" #include "protocol/OAuth2.hh" #include "util/Destroy.hh" #include "util/log/Log.hh" #include "xml/Node.hh" #include "xml/NodeSet.hh" #include // standard C++ library #include #include #include #include #include #include // for debugging only #include namespace gr { namespace { const std::string state_file = ".grive_state" ; } Drive::Drive( OAuth2& auth, const Json& options ) : m_auth( auth ), m_state( state_file, options ) { m_http_hdr.Add( "Authorization: Bearer " + m_auth.AccessToken() ) ; m_http_hdr.Add( "GData-Version: 3.0" ) ; } void Drive::FromRemote( const Entry& entry ) { // entries from change feed does not have the parent HREF, // so these checkings are done in normal entries only Resource *parent = m_state.FindByHref( entry.ParentHref() ) ; if ( parent != 0 && !parent->IsFolder() ) Log( "warning: entry %1% has parent %2% which is not a folder, ignored", entry.Title(), parent->Name(), log::verbose ) ; else if ( parent == 0 || !parent->IsInRootTree() ) Log( "file \"%1%\" parent doesn't exist, ignored", entry.Title(), log::verbose ) ; else m_state.FromRemote( entry ) ; } void Drive::FromChange( const Entry& entry ) { if ( entry.IsRemoved() ) Log( "file \"%1%\" represents a deletion, ignored", entry.Title(), log::verbose ) ; // folders go directly else m_state.FromRemote( entry ) ; } void Drive::SaveState() { m_state.Write( state_file ) ; } void Drive::SyncFolders( http::Agent *http ) { assert( http != 0 ) ; Log( "Synchronizing folders", log::info ) ; http::XmlResponse xml ; http->Get( feed_base + "/-/folder?max-results=50&showroot=true", &xml, m_http_hdr ) ; Feed feed( xml.Response() ) ; do { // first, get all collections from the query result for ( Feed::iterator i = feed.begin() ; i != feed.end() ; ++i ) { Entry e( *i ) ; if ( e.Kind() == "folder" ) { if ( e.ParentHrefs().size() != 1 ) Log( "folder \"%1%\" has multiple parents, ignored", e.Title(), log::verbose ) ; else if ( e.Title().find('/') != std::string::npos ) Log( "folder \"%1%\" contains a slash in its name, ignored", e.Title(), log::verbose ) ; else m_state.FromRemote( e ) ; } } } while ( feed.GetNext( http, m_http_hdr ) ) ; m_state.ResolveEntry() ; } void Drive::DetectChanges() { Log( "Reading local directories", log::info ) ; m_state.FromLocal( "." ) ; http::CurlAgent http ; long prev_stamp = m_state.ChangeStamp() ; Trace( "previous change stamp is %1%", prev_stamp ) ; SyncFolders( &http ) ; Log( "Reading remote server file list", log::info ) ; http::XmlResponse xrsp ; http.Get( feed_base + "?showfolders=true&showroot=true", &xrsp, m_http_hdr ) ; xml::Node resp = xrsp.Response() ; m_resume_link = resp["link"]. Find( "@rel", "http://schemas.google.com/g/2005#resumable-create-media" )["@href"] ; Feed feed( resp ) ; do { std::for_each( feed.begin(), feed.end(), boost::bind( &Drive::FromRemote, this, _1 ) ) ; } while ( feed.GetNext( &http, m_http_hdr ) ) ; // pull the changes feed if ( prev_stamp != -1 ) { http::ResponseLog log( "/tmp/changes-", ".xml", &xrsp ) ; Log( "Detecting changes from last sync", log::info ) ; http.Get( ChangesFeed(prev_stamp+1), &log, m_http_hdr ) ; Feed changes( xrsp.Response() ) ; std::for_each( changes.begin(), changes.end(), boost::bind( &Drive::FromChange, this, _1 ) ) ; } } void Drive::Update() { Log( "Synchronizing files", log::info ) ; http::CurlAgent http ; m_state.Sync( &http, m_http_hdr ) ; UpdateChangeStamp( &http ) ; } void Drive::DryRun() { Log( "Synchronizing files (dry-run)", log::info ) ; m_state.Sync( 0, m_http_hdr ) ; } void Drive::UpdateChangeStamp( http::Agent *http ) { assert( http != 0 ) ; // get changed feed http::XmlResponse xrsp ; http->Get( ChangesFeed(m_state.ChangeStamp()+1), &xrsp, m_http_hdr ) ; // we should go through the changes to see if it was really Grive to made that change // maybe by recording the updated timestamp and compare it? m_state.ChangeStamp( std::atoi(xrsp.Response()["docs:largestChangestamp"]["@value"].front().Value().c_str()) ) ; } } // end of namespace Grive-grive-93d696a/libgrive/src/drive/Drive.hh000066400000000000000000000027331177605442600213650ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "State.hh" #include "http/Header.hh" #include "util/Exception.hh" #include #include namespace gr { namespace http { class Agent ; } class Entry ; class OAuth2 ; class Json ; class Drive { public : Drive( OAuth2& auth, const Json& options ) ; void DetectChanges() ; void Update() ; void DryRun() ; void SaveState() ; struct Error : virtual Exception {} ; private : void SyncFolders( http::Agent *http ) ; void file(); void FromRemote( const Entry& entry ) ; void FromChange( const Entry& entry ) ; void UpdateChangeStamp( http::Agent *http ) ; private : OAuth2& m_auth ; http::Header m_http_hdr ; std::string m_resume_link ; State m_state ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/drive/Entry.cc000066400000000000000000000107151177605442600214020ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Entry.hh" #include "CommonUri.hh" #include "util/Crypt.hh" #include "util/log/Log.hh" #include "util/OS.hh" #include "xml/Node.hh" #include "xml/NodeSet.hh" #include #include namespace gr { /// construct an entry for the root folder Entry::Entry( ) : m_title ( "." ), m_kind ( "folder" ), m_resource_id ( "folder:root" ), m_self_href ( root_href ), m_create_link ( root_create ), m_change_stamp ( -1 ), m_is_removed ( false ) { } /// construct an entry for remote Entry::Entry( const xml::Node& n ) : m_change_stamp( -1 ), m_is_removed( false ) { Update( n ) ; } void Entry::Update( const xml::Node& n ) { m_title = n["title"] ; m_etag = n["@gd:etag"] ; m_filename = n["docs:suggestedFilename"] ; m_content_src = n["content"]["@src"] ; m_self_href = n["link"].Find( "@rel", "self" )["@href"] ; m_alt_self = n["link"].Find( "@rel", "http://schemas.google.com/docs/2007#alt-self" )["@href"] ; m_mtime = DateTime( n["updated"] ) ; m_resource_id = n["gd:resourceId"] ; m_md5 = n["docs:md5Checksum"] ; m_kind = n["category"].Find( "@scheme", "http://schemas.google.com/g/2005#kind" )["@label"] ; m_edit_link = n["link"].Find( "@rel", "http://schemas.google.com/g/2005#resumable-edit-media")["@href"] ; m_create_link = n["link"].Find( "@rel", "http://schemas.google.com/g/2005#resumable-create-media")["@href"] ; // changestamp only appear in change feed entries xml::NodeSet cs = n["docs:changestamp"]["@value"] ; m_change_stamp = cs.empty() ? -1 : std::atoi( cs.front().Value().c_str() ) ; m_parent_hrefs.clear( ) ; xml::NodeSet parents = n["link"].Find( "@rel", "http://schemas.google.com/docs/2007#parent" ) ; for ( xml::NodeSet::iterator i = parents.begin() ; i != parents.end() ; ++i ) m_parent_hrefs.push_back( (*i)["@href"] ) ; // convert to lower case for easy comparison std::transform( m_md5.begin(), m_md5.end(), m_md5.begin(), tolower ) ; m_is_removed = !n["gd:deleted"].empty() || !n["docs:removed"].empty() ; } const std::vector& Entry::ParentHrefs() const { return m_parent_hrefs ; } std::string Entry::Title() const { return m_title ; } std::string Entry::Filename() const { return m_filename ; } std::string Entry::Kind() const { return m_kind ; } std::string Entry::MD5() const { return m_md5 ; } DateTime Entry::MTime() const { return m_mtime ; } std::string Entry::SelfHref() const { return m_self_href ; } std::string Entry::AltSelf() const { return m_alt_self ; } std::string Entry::ParentHref() const { return m_parent_hrefs.empty() ? "" : m_parent_hrefs.front() ; } std::string Entry::ResourceID() const { return m_resource_id ; } std::string Entry::ETag() const { return m_etag ; } std::string Entry::ContentSrc() const { return m_content_src ; } std::string Entry::EditLink() const { return m_edit_link ; } std::string Entry::CreateLink() const { return m_create_link ; } void Entry::Swap( Entry& e ) { m_title.swap( e.m_title ) ; m_filename.swap( e.m_filename ) ; m_kind.swap( e.m_kind ) ; m_md5.swap( e.m_md5 ) ; m_etag.swap( e.m_etag ) ; m_resource_id.swap( e.m_resource_id ) ; m_parent_hrefs.swap( e.m_parent_hrefs ) ; m_self_href.swap( e.m_self_href ) ; m_alt_self.swap( e.m_alt_self ) ; m_content_src.swap( e.m_content_src ) ; m_edit_link.swap( e.m_edit_link ) ; m_create_link.swap( e.m_create_link ) ; m_mtime.Swap( e.m_mtime ) ; std::swap( m_change_stamp, e.m_change_stamp ) ; std::swap( m_is_removed, e.m_is_removed ) ; } long Entry::ChangeStamp() const { return m_change_stamp ; } bool Entry::IsChange() const { return m_change_stamp != -1 ; } bool Entry::IsRemoved() const { return m_is_removed ; } std::string Entry::Name() const { return m_kind == "file" ? m_filename : m_title ; } } // end of namespace Grive-grive-93d696a/libgrive/src/drive/Entry.hh000066400000000000000000000044701177605442600214150ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "util/DateTime.hh" #include "util/FileSystem.hh" #include #include #include namespace gr { namespace xml { class Node ; } /*! \brief corresponds to an "entry" in the resource feed This class is decodes an entry in the resource feed. It will stored the properties like title, filename and ETag etc in member variables. Normally entries are created by parsing the resource feed */ class Entry { public : Entry( ) ; explicit Entry( const xml::Node& n ) ; std::string Title() const ; std::string Filename() const ; std::string Kind() const ; std::string MD5() const ; DateTime MTime() const ; std::string Name() const ; std::string ResourceID() const ; std::string ETag() const ; std::string SelfHref() const ; std::string AltSelf() const ; std::string ParentHref() const ; std::string ContentSrc() const ; std::string EditLink() const ; std::string CreateLink() const ; long ChangeStamp() const ; bool IsChange() const ; bool IsRemoved() const ; const std::vector& ParentHrefs() const ; void Swap( Entry& e ) ; void Update( const xml::Node& entry ) ; private : std::string m_title ; std::string m_filename ; std::string m_kind ; std::string m_md5 ; std::string m_etag ; std::string m_resource_id ; std::vector m_parent_hrefs ; std::string m_self_href ; std::string m_alt_self ; std::string m_content_src ; std::string m_edit_link ; std::string m_create_link ; long m_change_stamp ; DateTime m_mtime ; bool m_is_removed ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/drive/Feed.cc000066400000000000000000000041201177605442600211350ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Feed.hh" #include "http/Agent.hh" #include "http/XmlResponse.hh" #include "xml/NodeSet.hh" #include namespace gr { Feed::Feed( const xml::Node& root ) : m_root ( root ), m_entries ( m_root["entry"] ) { } void Feed::Assign( const xml::Node& root ) { m_root = root ; m_entries = m_root["entry"] ; } Feed::iterator Feed::begin() const { return iterator( m_entries.begin() ) ; } Feed::iterator Feed::end() const { return iterator( m_entries.end() ) ; } std::string Feed::Next() const { xml::NodeSet nss = m_root["link"].Find( "@rel", "next" ) ; return nss.empty() ? "" : std::string(nss["@href"]) ; } bool Feed::GetNext( http::Agent *http, const http::Header& auth ) { assert( http != 0 ) ; xml::NodeSet nss = m_root["link"].Find( "@rel", "next" ) ; if ( !nss.empty() ) { http::XmlResponse xrsp ; http->Get( nss["@href"], &xrsp, auth ) ; m_root = xrsp.Response() ; m_entries = m_root["entry"] ; return true ; } else return false ; } Feed::iterator::iterator( ) { } Feed::iterator::iterator( xml::Node::iterator i ) { // for some reason, gcc 4.4.4 doesn't allow me to initialize the base class // in the initializer. I have no choice but to initialize here. base_reference() = i ; } Feed::iterator::reference Feed::iterator::dereference() const { return Entry( *base_reference() ) ; } } // end of namespace Grive-grive-93d696a/libgrive/src/drive/Feed.hh000066400000000000000000000031531177605442600211540ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Entry.hh" #include "xml/Node.hh" #include "xml/NodeSet.hh" #include #include namespace gr { namespace http { class Agent ; class Header ; } class Feed { public : class iterator ; public : explicit Feed( const xml::Node& root ) ; void Assign( const xml::Node& root ) ; iterator begin() const ; iterator end() const ; std::string Next() const ; bool GetNext( http::Agent *http, const http::Header& auth ) ; private : xml::Node m_root ; xml::NodeSet m_entries ; } ; class Feed::iterator : public boost::iterator_adaptor< Feed::iterator, xml::Node::iterator, Entry, boost::random_access_traversal_tag, Entry > { public : iterator() ; explicit iterator( xml::Node::iterator i ) ; private : friend class boost::iterator_core_access; reference dereference() const ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/drive/Resource.cc000066400000000000000000000375441177605442600221010ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Resource.hh" #include "CommonUri.hh" #include "Entry.hh" #include "http/Agent.hh" #include "http/Download.hh" #include "http/Header.hh" // #include "http/ResponseLog.hh" #include "http/StringResponse.hh" #include "http/XmlResponse.hh" #include "protocol/Json.hh" #include "util/CArray.hh" #include "util/Crypt.hh" #include "util/log/Log.hh" #include "util/OS.hh" #include "util/StdioFile.hh" #include "xml/Node.hh" #include "xml/NodeSet.hh" #include "xml/String.hh" #include #include #include // for debugging #include namespace gr { // hard coded XML file const std::string xml_meta = "\n" "" "" "%2%" "" ; /// default constructor creates the root folder Resource::Resource() : m_name ( "." ), m_kind ( "folder" ), m_id ( "folder:root" ), m_href ( root_href ), m_create ( root_create ), m_parent ( 0 ), m_state ( sync ) { } Resource::Resource( const std::string& name, const std::string& kind ) : m_name ( name ), m_kind ( kind ), m_parent ( 0 ), m_state ( unknown ) { } void Resource::SetState( State new_state ) { // only the new and delete states need to be set recursively assert( new_state == remote_new || new_state == remote_deleted || new_state == local_new || new_state == local_deleted ) ; m_state = new_state ; std::for_each( m_child.begin(), m_child.end(), boost::bind( &Resource::SetState, _1, new_state ) ) ; } void Resource::FromRemoteFolder( const Entry& remote, const DateTime& last_sync ) { fs::path path = Path() ; if ( remote.CreateLink().empty() ) Log( "folder %1% is read-only", path, log::verbose ) ; // already sync if ( fs::is_directory( path ) ) { Log( "folder %1% is in sync", path, log::verbose ) ; m_state = sync ; } // remote file created after last sync, so remote is newer else if ( remote.MTime() > last_sync ) { if ( fs::exists( path ) ) { // TODO: handle type change Log( "%1% changed from folder to file", path, log::verbose ) ; m_state = sync ; } else { // make all children as remote_new, if any Log( "folder %1% is created in remote", path, log::verbose ) ; SetState( remote_new ) ; } } else { if ( fs::exists( path ) ) { // TODO: handle type chage Log( "%1% changed from file to folder", path, log::verbose ) ; m_state = sync ; } else { Log( "folder %1% is deleted in local", path, log::verbose ) ; SetState( local_deleted ) ; } } } /// Update the state according to information (i.e. Entry) from remote. This function /// compares the modification time and checksum of both copies and determine which /// one is newer. void Resource::FromRemote( const Entry& remote, const DateTime& last_sync ) { // sync folder if ( remote.Kind() == "folder" && IsFolder() ) FromRemoteFolder( remote, last_sync ) ; else FromRemoteFile( remote, last_sync ) ; AssignIDs( remote ) ; assert( m_state != unknown ) ; if ( m_state == remote_new || m_state == remote_changed ) { m_md5 = remote.MD5() ; m_mtime = remote.MTime() ; } } void Resource::AssignIDs( const Entry& remote ) { // the IDs from change feed entries are different if ( !remote.IsChange() ) { m_id = remote.ResourceID() ; m_href = remote.SelfHref() ; m_edit = remote.EditLink() ; m_create = remote.CreateLink() ; m_content = remote.ContentSrc() ; m_etag = remote.ETag() ; } } void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) { assert( m_parent != 0 ) ; fs::path path = Path() ; // recursively create/delete folder if ( m_parent->m_state == remote_new || m_parent->m_state == remote_deleted || m_parent->m_state == local_new || m_parent->m_state == local_deleted ) { Log( "file %1% parent %2% recursively in %3% (%4%)", path, ( m_parent->m_state == remote_new || m_parent->m_state == local_new ) ? "created" : "deleted", ( m_parent->m_state == remote_new || m_parent->m_state == remote_deleted ) ? "remote" : "local", m_parent->m_state, log::verbose ) ; m_state = m_parent->m_state ; } // local not exists else if ( !fs::exists( path ) ) { Trace( "file %1% change stamp = %2%", Path(), remote.ChangeStamp() ) ; if ( remote.MTime() > last_sync || remote.ChangeStamp() > 0 ) { Log( "file %1% is created in remote (change %2%)", path, remote.ChangeStamp(), log::verbose ) ; m_state = remote_new ; } else { Log( "file %1% is deleted in local", path, log::verbose ) ; m_state = local_deleted ; } } // if checksum is equal, no need to compare the mtime else if ( remote.MD5() == m_md5 ) { Log( "file %1% is already in sync", Path(), log::verbose ) ; m_state = sync ; } // use mtime to check which one is more recent else { assert( m_state != unknown ) ; // if remote is modified if ( remote.MTime() > m_mtime ) { Log( "file %1% is changed in remote", path, log::verbose ) ; m_state = remote_changed ; } // remote also has the file, so it's not new in local else if ( m_state == local_new || m_state == remote_deleted ) { Log( "file %1% is changed in local", path, log::verbose ) ; m_state = local_changed ; } else Trace( "file %1% state is %2%", m_name, m_state ) ; } } /// Update the resource with the attributes of local file or directory. This /// function will propulate the fields in m_entry. void Resource::FromLocal( const DateTime& last_sync ) { fs::path path = Path() ; assert( fs::exists( path ) ) ; // root folder is always in sync if ( !IsRoot() ) { m_mtime = os::FileCTime( path ) ; // follow parent recursively if ( m_parent->m_state == local_new || m_parent->m_state == local_deleted ) m_state = local_new ; // if the file is not created after last sync, assume file is // remote_deleted first, it will be updated to sync/remote_changed // in FromRemote() else m_state = ( m_mtime > last_sync ? local_new : remote_deleted ) ; m_name = Path2Str( path.filename() ) ; m_kind = fs::is_directory(path) ? "folder" : "file" ; m_md5 = fs::is_directory(path) ? "" : crypt::MD5::Get( path ) ; } assert( m_state != unknown ) ; } std::string Resource::SelfHref() const { return m_href ; } std::string Resource::Name() const { return m_name ; } std::string Resource::ResourceID() const { return m_id ; } const Resource* Resource::Parent() const { assert( m_parent == 0 || m_parent->IsFolder() ) ; return m_parent ; } Resource* Resource::Parent() { assert( m_parent == 0 || m_parent->IsFolder() ) ; return m_parent ; } void Resource::AddChild( Resource *child ) { assert( child != 0 ) ; assert( child->m_parent == 0 || child->m_parent == this ) ; assert( child != this ) ; child->m_parent = this ; m_child.push_back( child ) ; } void Resource::Swap( Resource& coll ) { m_name.swap( coll.m_name ) ; m_kind.swap( coll.m_kind ) ; m_md5.swap( coll.m_md5 ) ; m_etag.swap( coll.m_etag ) ; m_id.swap( coll.m_id ) ; m_href.swap( coll.m_href ) ; m_content.swap( coll.m_content ) ; m_edit.swap( coll.m_edit ) ; m_create.swap( coll.m_create ) ; m_mtime.Swap( coll.m_mtime ) ; std::swap( m_parent, coll.m_parent ) ; m_child.swap( coll.m_child ) ; std::swap( m_state, coll.m_state ) ; } bool Resource::IsFolder() const { return m_kind == "folder" ; } fs::path Resource::Path() const { assert( m_parent != this ) ; assert( m_parent == 0 || m_parent->IsFolder() ) ; return m_parent != 0 ? (m_parent->Path() / m_name) : m_name ; } bool Resource::IsInRootTree() const { assert( m_parent == 0 || m_parent->IsFolder() ) ; return m_parent == 0 ? (SelfHref() == root_href) : m_parent->IsInRootTree() ; } Resource* Resource::FindChild( const std::string& name ) { for ( std::vector::iterator i = m_child.begin() ; i != m_child.end() ; ++i ) { assert( (*i)->m_parent == this ) ; if ( (*i)->m_name == name ) return *i ; } return 0 ; } // try to change the state to "sync" void Resource::Sync( http::Agent *http, const http::Header& auth ) { assert( m_state != unknown ) ; assert( !IsRoot() || m_state == sync ) ; // root folder is already synced SyncSelf( http, auth ) ; // if myself is deleted, no need to do the childrens if ( m_state != local_deleted && m_state != remote_deleted ) std::for_each( m_child.begin(), m_child.end(), boost::bind( &Resource::Sync, _1, http, auth ) ) ; } void Resource::SyncSelf( http::Agent* http, const http::Header& auth ) { assert( !IsRoot() || m_state == sync ) ; // root is always sync assert( IsRoot() || http == 0 || fs::is_directory( m_parent->Path() ) ) ; assert( IsRoot() || m_parent->m_state != remote_deleted ) ; assert( IsRoot() || m_parent->m_state != local_deleted ) ; const fs::path path = Path() ; switch ( m_state ) { case local_new : Log( "sync %1% doesn't exist in server, uploading", path, log::info ) ; if ( http != 0 && Create( http, auth ) ) m_state = sync ; break ; case local_deleted : Log( "sync %1% deleted in local. deleting remote", path, log::info ) ; if ( http != 0 ) DeleteRemote( http, auth ) ; break ; case local_changed : Log( "sync %1% changed in local. uploading", path, log::info ) ; if ( http != 0 && EditContent( http, auth ) ) m_state = sync ; break ; case remote_new : Log( "sync %1% created in remote. creating local", path, log::info ) ; if ( http != 0 ) { if ( IsFolder() ) fs::create_directories( path ) ; else Download( http, path, auth ) ; m_state = sync ; } break ; case remote_changed : assert( !IsFolder() ) ; Log( "sync %1% changed in remote. downloading", path, log::info ) ; if ( http != 0 ) { Download( http, path, auth ) ; m_state = sync ; } break ; case remote_deleted : Log( "sync %1% deleted in remote. deleting local", path, log::info ) ; if ( http != 0 ) DeleteLocal() ; break ; case sync : Log( "sync %1% already in sync", path, log::verbose ) ; break ; // shouldn't go here case unknown : assert( false ) ; break ; default : break ; } } /// this function doesn't really remove the local file. it renames it. void Resource::DeleteLocal() { static const boost::format trash_file( "%1%-%2%" ) ; assert( m_parent != 0 ) ; fs::path parent = m_parent->Path() ; fs::path dest = ".trash" / parent / Name() ; std::size_t idx = 1 ; while ( fs::exists( dest ) && idx != 0 ) dest = ".trash" / parent / (boost::format(trash_file) % Name() % idx++).str() ; // wrap around! just remove the file if ( idx == 0 ) fs::remove_all( Path() ) ; else { fs::create_directories( dest.parent_path() ) ; fs::rename( Path(), dest ) ; } } void Resource::DeleteRemote( http::Agent *http, const http::Header& auth ) { assert( http != 0 ) ; http::StringResponse str ; try { http::Header hdr( auth ) ; hdr.Add( "If-Match: " + m_etag ) ; // doesn't know why, but an update before deleting seems to work always http::XmlResponse xml ; http->Get( m_href, &xml, hdr ) ; AssignIDs( Entry( xml.Response() ) ) ; http->Custom( "DELETE", m_href, &str, hdr ) ; } catch ( Exception& e ) { // don't rethrow here. there are some cases that I don't know why // the delete will fail. Trace( "Exception %1% %2%", boost::diagnostic_information(e), str.Response() ) ; } } void Resource::Download( http::Agent* http, const fs::path& file, const http::Header& auth ) const { assert( http != 0 ) ; http::Download dl( file.string(), http::Download::NoChecksum() ) ; long r = http->Get( m_content, &dl, auth ) ; if ( r <= 400 ) { if ( m_mtime != DateTime() ) os::SetFileTime( file, m_mtime ) ; else Log( "encountered zero date time after downloading %1%", file, log::warning ) ; } } bool Resource::EditContent( http::Agent* http, const http::Header& auth ) { assert( http != 0 ) ; assert( m_parent != 0 ) ; assert( m_parent->m_state == sync ) ; // upload link missing means that file is read only if ( m_edit.empty() ) { Log( "Cannot upload %1%: file read-only. %2%", m_name, m_state, log::warning ) ; return false ; } return Upload( http, m_edit, auth, false ) ; } bool Resource::Create( http::Agent* http, const http::Header& auth ) { assert( http != 0 ) ; assert( m_parent != 0 ) ; assert( m_parent->IsFolder() ) ; assert( m_parent->m_state == sync ) ; if ( IsFolder() ) { std::string uri = feed_base ; if ( !m_parent->IsRoot() ) uri += ("/" + http->Escape(m_parent->m_id) + "/contents") ; std::string meta = (boost::format( xml_meta ) % "folder" % xml::Escape(m_name) ).str() ; http::Header hdr( auth ) ; hdr.Add( "Content-Type: application/atom+xml" ) ; http::XmlResponse xml ; // http::ResponseLog log( "create", ".xml", &xml ) ; http->Post( uri, meta, &xml, hdr ) ; AssignIDs( Entry( xml.Response() ) ) ; return true ; } else if ( !m_parent->m_create.empty() ) { return Upload( http, m_parent->m_create + "?convert=false", auth, true ) ; } else { Log( "parent of %1% does not exist: cannot upload", Name(), log::warning ) ; return false ; } } bool Resource::Upload( http::Agent* http, const std::string& link, const http::Header& auth, bool post ) { assert( http != 0 ) ; StdioFile file( Path() ) ; // TODO: upload in chunks std::string data ; char buf[4096] ; std::size_t count = 0 ; while ( (count = file.Read( buf, sizeof(buf) )) > 0 ) data.append( buf, count ) ; std::ostringstream xcontent_len ; xcontent_len << "X-Upload-Content-Length: " << data.size() ; http::Header hdr( auth ) ; hdr.Add( "Content-Type: application/atom+xml" ) ; hdr.Add( "X-Upload-Content-Type: application/octet-stream" ) ; hdr.Add( xcontent_len.str() ) ; hdr.Add( "If-Match: " + m_etag ) ; hdr.Add( "Expect:" ) ; std::string meta = (boost::format( xml_meta ) % m_kind % xml::Escape(m_name) ).str() ; http::StringResponse str ; if ( post ) http->Post( link, meta, &str, hdr ) ; else http->Put( link, meta, &str, hdr ) ; http::Header uphdr ; uphdr.Add( "Expect:" ) ; uphdr.Add( "Accept:" ) ; // the content upload URL is in the "Location" HTTP header std::string uplink = http->RedirLocation() ; http::XmlResponse xml ; http->Put( uplink, data, &xml, uphdr ) ; AssignIDs( Entry( xml.Response() ) ) ; return true ; } Resource::iterator Resource::begin() const { return m_child.begin() ; } Resource::iterator Resource::end() const { return m_child.end() ; } std::size_t Resource::size() const { return m_child.size() ; } std::ostream& operator<<( std::ostream& os, Resource::State s ) { static const char *state[] = { "sync", "local_new", "local_changed", "local_deleted", "remote_new", "remote_changed", "remote_deleted" } ; assert( s >= 0 && s < Count(state) ) ; return os << state[s] ; } std::string Resource::StateStr() const { std::ostringstream ss ; ss << m_state ; return ss.str() ; } std::string Resource::MD5() const { return m_md5 ; } bool Resource::IsRoot() const { return m_parent == 0 ; } bool Resource::HasID() const { return !m_href.empty() && !m_id.empty() ; } } // end of namespace namespace std { void swap( gr::Resource& c1, gr::Resource& c2 ) { c1.Swap( c2 ) ; } } Grive-grive-93d696a/libgrive/src/drive/Resource.hh000066400000000000000000000104421177605442600220770ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "util/DateTime.hh" #include "util/Exception.hh" #include "util/FileSystem.hh" #include #include #include namespace gr { namespace http { class Agent ; class Header ; } class Entry ; /*! \brief A resource can be a file or a folder in the google drive The google drive contains a number of resources, which is represented by this class. It also contains linkage to other resources, such as parent and childrens. */ class Resource { public : struct Error : virtual Exception {} ; typedef std::vector Children ; typedef Children::const_iterator iterator ; public : Resource() ; Resource( const std::string& name, const std::string& kind ) ; // default copy ctor & op= are fine void Swap( Resource& coll ) ; bool IsFolder() const ; std::string Name() const ; std::string SelfHref() const ; std::string ResourceID() const ; const Resource* Parent() const ; Resource* Parent() ; void AddChild( Resource *child ) ; Resource* FindChild( const std::string& title ) ; fs::path Path() const ; bool IsInRootTree() const ; bool IsRoot() const ; bool HasID() const ; std::string MD5() const ; void FromRemote( const Entry& remote, const DateTime& last_sync ) ; void FromLocal( const DateTime& last_sync ) ; void Sync( http::Agent* http, const http::Header& auth ) ; // children access iterator begin() const ; iterator end() const ; std::size_t size() const ; std::string StateStr() const ; private : /// State of the resource. indicating what to do with the resource enum State { /// The best state: the file is the same in remote and in local. sync, /// Resource created in local, but remote does not have it. /// We should create the resource in google drive and upload new content local_new, /// Resource exists in both local & remote, but changes in local is newer /// than remote. We should upload local copy to overwrite remote. local_changed, /// Resource deleted from local since last time grive has checked. local_deleted, /// Resource created in google drive, but not exist in local. /// We should download the file. remote_new, /// Resource exists in both local & remote, but remote is newer. remote_changed, /// Resource delete in remote, need to delete in local remote_deleted, /// invalid value unknown } ; friend std::ostream& operator<<( std::ostream& os, State s ) ; private : void SetState( State new_state ) ; void Download( http::Agent* http, const fs::path& file, const http::Header& auth ) const ; bool EditContent( http::Agent* http, const http::Header& auth ) ; bool Create( http::Agent* http, const http::Header& auth ) ; bool Upload( http::Agent* http, const std::string& link, const http::Header& auth, bool post ) ; void FromRemoteFolder( const Entry& remote, const DateTime& last_sync ) ; void FromRemoteFile( const Entry& remote, const DateTime& last_sync ) ; void DeleteLocal() ; void DeleteRemote( http::Agent* http, const http::Header& auth ) ; void AssignIDs( const Entry& remote ) ; void SyncSelf( http::Agent* http, const http::Header& auth ) ; private : std::string m_name ; std::string m_kind ; std::string m_md5 ; DateTime m_mtime ; std::string m_id ; std::string m_href ; std::string m_edit ; std::string m_create ; std::string m_content ; std::string m_etag ; // not owned Resource *m_parent ; std::vector m_child ; State m_state ; } ; } // end of namespace namespace std { void swap( gr::Resource& c1, gr::Resource& c2 ) ; } Grive-grive-93d696a/libgrive/src/drive/ResourceTree.cc000066400000000000000000000075071177605442600227150ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ResourceTree.hh" #include "CommonUri.hh" #include "protocol/Json.hh" #include "util/Destroy.hh" #include "util/log/Log.hh" #include #include namespace gr { using namespace details ; ResourceTree::ResourceTree( ) : m_root( new Resource ) { m_set.insert( m_root ) ; } ResourceTree::ResourceTree( const ResourceTree& fs ) : m_root( 0 ) { const Set& s = fs.m_set.get() ; for ( Set::const_iterator i = s.begin() ; i != s.end() ; ++i ) { Resource *c = new Resource( **i ) ; if ( c->SelfHref() == root_href ) m_root = c ; m_set.insert( c ) ; } assert( m_root != 0 ) ; } ResourceTree::~ResourceTree( ) { Clear() ; } void ResourceTree::Clear() { // delete all pointers const Set& s = m_set.get() ; std::for_each( s.begin(), s.end(), Destroy() ) ; m_set.clear() ; m_root = 0 ; } Resource* ResourceTree::Root() { assert( m_root != 0 ) ; return m_root ; } const Resource* ResourceTree::Root() const { assert( m_root != 0 ) ; return m_root ; } void ResourceTree::Swap( ResourceTree& fs ) { m_set.swap( fs.m_set ) ; } ResourceTree& ResourceTree::operator=( const ResourceTree& fs ) { ResourceTree tmp( fs ) ; Swap( tmp ) ; return *this ; } Resource* ResourceTree::FindByHref( const std::string& href ) { // for the resource that not yet have href (e.g. not yet fetched from server) // their href will be empty. if ( href.empty() ) return 0 ; HrefMap& map = m_set.get() ; HrefMap::iterator i = map.find( href ) ; return i != map.end() ? *i : 0 ; } const Resource* ResourceTree::FindByHref( const std::string& href ) const { const HrefMap& map = m_set.get() ; HrefMap::const_iterator i = map.find( href ) ; return i != map.end() ? *i : 0 ; } /// Unlike other search functions, this one does not depend on the multi-index /// container. It traverses the tree instead. Resource* ResourceTree::FindByPath( const fs::path& path ) { Resource *current = m_root ; for ( fs::path::iterator i = path.begin() ; i != path.end() && current != 0 ; ++i ) { Trace( "path it = %1%", *i ) ; // current directory if ( *i == "." ) continue ; else if ( *i == ".." ) current = current->Parent() ; else current = current->FindChild( Path2Str(*i) ) ; } return current ; } /// Reinsert should be called when the ID/HREF were updated bool ResourceTree::ReInsert( Resource *coll ) { Set& s = m_set.get() ; Set::iterator i = s.find( coll ) ; if ( i != s.end() ) { s.erase( i ) ; m_set.insert( coll ) ; return true ; } else return false ; } void ResourceTree::Insert( Resource *coll ) { m_set.insert( coll ) ; } void ResourceTree::Erase( Resource *coll ) { Set& s = m_set.get() ; s.erase( s.find( coll ) ) ; } void ResourceTree::Update( Resource *coll, const Entry& e, const DateTime& last_sync ) { assert( coll != 0 ) ; coll->FromRemote( e, last_sync ) ; ReInsert( coll ) ; } ResourceTree::iterator ResourceTree::begin() { return m_set.get().begin() ; } ResourceTree::iterator ResourceTree::end() { return m_set.get().end() ; } } // end of namespace Grive-grive-93d696a/libgrive/src/drive/ResourceTree.hh000066400000000000000000000051611177605442600227210ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Resource.hh" #include "util/FileSystem.hh" #include #include #include #include namespace gr { class Json ; namespace details { using namespace boost::multi_index ; struct ByID {} ; struct ByHref {} ; struct ByIdentity {} ; typedef multi_index_container< Resource*, indexed_by< hashed_non_unique, const_mem_fun >, hashed_non_unique, const_mem_fun >, hashed_unique, identity > > > Folders ; typedef Folders::index::type IDMap ; typedef Folders::index::type HrefMap ; typedef Folders::index::type Set ; } /*! \brief A simple container for storing folders This class stores a set of folders and provide fast search access from ID, HREF etc. It is a wrapper around multi_index_container from Boost library. */ class ResourceTree { public : typedef details::Set::iterator iterator ; public : ResourceTree( ) ; ResourceTree( const ResourceTree& fs ) ; ~ResourceTree( ) ; void Swap( ResourceTree& fs ) ; ResourceTree& operator=( const ResourceTree& fs ) ; Resource* FindByHref( const std::string& href ) ; const Resource* FindByHref( const std::string& href ) const ; Resource* FindByPath( const fs::path& path ) ; Resource* FindByID( const std::string& id ) ; bool ReInsert( Resource *coll ) ; void Insert( Resource *coll ) ; void Erase( Resource *coll ) ; void Update( Resource *coll, const Entry& e, const DateTime& last_sync ) ; Resource* Root() ; const Resource* Root() const ; iterator begin() ; iterator end() ; private : void Clear() ; private : details::Folders m_set ; Resource* m_root ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/drive/State.cc000066400000000000000000000147331177605442600213650ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "State.hh" #include "Entry.hh" #include "Resource.hh" #include "CommonUri.hh" #include "http/Agent.hh" #include "http/Header.hh" #include "util/Crypt.hh" #include "util/log/Log.hh" #include "protocol/Json.hh" #include namespace gr { State::State( const fs::path& filename, const Json& options ) : m_cstamp( -1 ) { Read( filename ) ; // the "-f" option will make grive always thinks remote is newer Json force ; if ( options.Get("force", force) && force.Bool() ) m_last_sync = DateTime() ; Log( "last sync time: %1%", m_last_sync, log::verbose ) ; } State::~State() { } /// Synchronize local directory. Build up the resource tree from files and folders /// of local directory. void State::FromLocal( const fs::path& p ) { FromLocal( p, m_res.Root() ) ; } bool State::IsIgnore( const std::string& filename ) { return filename[0] == '.' ; } void State::FromLocal( const fs::path& p, gr::Resource* folder ) { assert( folder != 0 ) ; assert( folder->IsFolder() ) ; // sync the folder itself folder->FromLocal( m_last_sync ) ; for ( fs::directory_iterator i( p ) ; i != fs::directory_iterator() ; ++i ) { std::string fname = Path2Str(i->path().filename()) ; // Trace( "found file %1%", i->path() ) ; if ( IsIgnore(fname) ) Log( "file %1% is ignored by grive", fname, log::verbose ) ; // check for broken symblic links else if ( !fs::exists( i->path() ) ) Log( "file %1% doesn't exist (broken link?), ignored", i->path(), log::verbose ) ; else { // if the Resource object of the child already exists, it should // have been so no need to do anything here Resource *c = folder->FindChild( fname ) ; if ( c == 0 ) { c = new Resource( fname, fs::is_directory(i->path()) ? "folder" : "file" ) ; folder->AddChild( c ) ; m_res.Insert( c ) ; } c->FromLocal( m_last_sync ) ; if ( fs::is_directory( i->path() ) ) FromLocal( *i, c ) ; } } } void State::FromRemote( const Entry& e ) { std::string fn = e.Filename() ; if ( IsIgnore( e.Name() ) ) Log( "%1% %2% is ignored by grive", e.Kind(), e.Name(), log::verbose ) ; // common checkings else if ( e.Kind() != "folder" && (fn.empty() || e.ContentSrc().empty()) ) Log( "%1% \"%2%\" is a google document, ignored", e.Kind(), e.Name(), log::verbose ) ; else if ( fn.find('/') != fn.npos ) Log( "%1% \"%2%\" contains a slash in its name, ignored", e.Kind(), e.Name(), log::verbose ) ; else if ( !e.IsChange() && e.ParentHrefs().size() != 1 ) Log( "%1% \"%2%\" has multiple parents, ignored", e.Kind(), e.Name(), log::verbose ) ; else if ( e.IsChange() ) FromChange( e ) ; else if ( !Update( e ) ) { m_unresolved.push_back( e ) ; } } void State::ResolveEntry() { while ( !m_unresolved.empty() ) { if ( TryResolveEntry() == 0 ) break ; } } std::size_t State::TryResolveEntry() { assert( !m_unresolved.empty() ) ; std::size_t count = 0 ; std::vector& en = m_unresolved ; for ( std::vector::iterator i = en.begin() ; i != en.end() ; ) { if ( Update( *i ) ) { i = en.erase( i ) ; count++ ; } else ++i ; } return count ; } void State::FromChange( const Entry& e ) { assert( e.IsChange() ) ; assert( !IsIgnore( e.Name() ) ) ; // entries in the change feed is always treated as newer in remote, // so we override the last sync time to 0 if ( Resource *res = m_res.FindByHref( e.AltSelf() ) ) m_res.Update( res, e, DateTime() ) ; } bool State::Update( const Entry& e ) { assert( !e.IsChange() ) ; assert( !e.ParentHref().empty() ) ; if ( Resource *res = m_res.FindByHref( e.SelfHref() ) ) { m_res.Update( res, e, m_last_sync ) ; return true ; } else if ( Resource *parent = m_res.FindByHref( e.ParentHref() ) ) { assert( parent->IsFolder() ) ; // see if the entry already exist in local std::string name = e.Name() ; Resource *child = parent->FindChild( name ) ; if ( child != 0 ) { // since we are updating the ID and Href, we need to remove it and re-add it. m_res.Update( child, e, m_last_sync ) ; } // folder entry exist in google drive, but not local. we should create // the directory else if ( e.Kind() == "folder" || !e.Filename().empty() ) { // first create a dummy resource and update it later child = new Resource( name, e.Kind() ) ; parent->AddChild( child ) ; m_res.Insert( child ) ; // update the state of the resource m_res.Update( child, e, m_last_sync ) ; } return true ; } else return false ; } Resource* State::FindByHref( const std::string& href ) { return m_res.FindByHref( href ) ; } Resource* State::Find( const fs::path& path ) { return m_res.FindByPath( path ) ; } State::iterator State::begin() { return m_res.begin() ; } State::iterator State::end() { return m_res.end() ; } void State::Read( const fs::path& filename ) { try { Json json = Json::ParseFile( filename.string() ) ; Json last_sync = json["last_sync"] ; m_last_sync.Assign( last_sync["sec"].Int(), last_sync["nsec"].Int() ) ; m_cstamp = json["change_stamp"].Int() ; } catch ( Exception& ) { m_last_sync.Assign(0) ; } } void State::Write( const fs::path& filename ) const { Json last_sync ; last_sync.Add( "sec", Json(m_last_sync.Sec() ) ); last_sync.Add( "nsec", Json(m_last_sync.NanoSec() ) ); Json result ; result.Add( "last_sync", last_sync ) ; result.Add( "change_stamp", Json(m_cstamp) ) ; std::ofstream fs( filename.string().c_str() ) ; fs << result ; } void State::Sync( http::Agent *http, const http::Header& auth ) { m_res.Root()->Sync( http, auth ) ; m_last_sync = DateTime::Now() ; } long State::ChangeStamp() const { return m_cstamp ; } void State::ChangeStamp( long cstamp ) { Log( "change stamp is set to %1%", cstamp, log::verbose ) ; m_cstamp = cstamp ; } } // end of namespace Grive-grive-93d696a/libgrive/src/drive/State.hh000066400000000000000000000037341177605442600213760ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "ResourceTree.hh" #include "util/DateTime.hh" #include "util/FileSystem.hh" #include namespace gr { namespace http { class Agent ; class Header ; } class Json ; class Resource ; class Entry ; class State { public : typedef ResourceTree::iterator iterator ; public : explicit State( const fs::path& filename, const Json& options ) ; ~State() ; void FromLocal( const fs::path& p ) ; void FromRemote( const Entry& e ) ; void ResolveEntry() ; void Read( const fs::path& filename ) ; void Write( const fs::path& filename ) const ; Resource* FindByHref( const std::string& href ) ; Resource* FindByID( const std::string& id ) ; Resource* Find( const fs::path& path ) ; void Sync( http::Agent *http, const http::Header& auth ) ; iterator begin() ; iterator end() ; long ChangeStamp() const ; void ChangeStamp( long cstamp ) ; private : void FromLocal( const fs::path& p, Resource *folder ) ; void FromChange( const Entry& e ) ; bool Update( const Entry& e ) ; std::size_t TryResolveEntry() ; static bool IsIgnore( const std::string& filename ) ; private : ResourceTree m_res ; DateTime m_last_sync ; long m_cstamp ; std::vector m_unresolved ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/http/000077500000000000000000000000001177605442600176345ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/src/http/Agent.hh000066400000000000000000000030271177605442600212150ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include namespace gr { namespace http { class Header ; class Receivable ; class Agent { public : virtual long Put( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) = 0 ; virtual long Get( const std::string& url, Receivable *dest, const Header& hdr ) = 0 ; virtual long Post( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) = 0 ; virtual long Custom( const std::string& method, const std::string& url, Receivable *dest, const Header& hdr ) = 0 ; virtual std::string RedirLocation() const = 0 ; virtual std::string Escape( const std::string& str ) = 0 ; virtual std::string Unescape( const std::string& str ) = 0 ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/http/CurlAgent.cc000066400000000000000000000143351177605442600220350ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "CurlAgent.hh" #include "Download.hh" #include "Error.hh" #include "Header.hh" #include "Receivable.hh" #include "util/log/Log.hh" #include // dependent libraries #include #include #include #include #include #include #include #include namespace { using namespace gr::http ; size_t ReadCallback( void *ptr, std::size_t size, std::size_t nmemb, std::string *data ) { assert( ptr != 0 ) ; assert( data != 0 ) ; std::size_t count = std::min( size * nmemb, data->size() ) ; if ( count > 0 ) { std::memcpy( ptr, &(*data)[0], count ) ; data->erase( 0, count ) ; } return count ; } } // end of local namespace namespace gr { namespace http { struct CurlAgent::Impl { CURL *curl ; std::string location ; } ; CurlAgent::CurlAgent() : m_pimpl( new Impl ) { m_pimpl->curl = ::curl_easy_init(); } void CurlAgent::Init() { ::curl_easy_reset( m_pimpl->curl ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_SSL_VERIFYPEER, 0L ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_SSL_VERIFYHOST, 0L ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_HEADERFUNCTION, &CurlAgent::HeaderCallback ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_WRITEHEADER , this ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_HEADER, 0L ) ; } CurlAgent::~CurlAgent() { ::curl_easy_cleanup( m_pimpl->curl ); } std::size_t CurlAgent::HeaderCallback( void *ptr, size_t size, size_t nmemb, CurlAgent *pthis ) { char *str = reinterpret_cast(ptr) ; std::string line( str, str + size*nmemb ) ; static const std::string loc = "Location: " ; std::size_t pos = line.find( loc ) ; if ( pos != line.npos ) { std::size_t end_pos = line.find( "\r\n", pos ) ; pthis->m_pimpl->location = line.substr( loc.size(), end_pos - loc.size() ) ; } return size*nmemb ; } std::size_t CurlAgent::Receive( void* ptr, size_t size, size_t nmemb, Receivable *recv ) { assert( recv != 0 ) ; return recv->OnData( ptr, size * nmemb ) ; } long CurlAgent::ExecCurl( const std::string& url, Receivable *dest, const http::Header& hdr ) { CURL *curl = m_pimpl->curl ; assert( curl != 0 ) ; char error[CURL_ERROR_SIZE] = {} ; ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error ) ; ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlAgent::Receive ) ; ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, dest ) ; SetHeader( hdr ) ; dest->Clear() ; CURLcode curl_code = ::curl_easy_perform(curl); long http_code = 0; ::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); Trace( "HTTP response %1%", http_code ) ; ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, 0 ) ; if ( curl_code != CURLE_OK || http_code >= 400 ) { BOOST_THROW_EXCEPTION( Error() << CurlCode( curl_code ) << HttpResponse( http_code ) << Url( url ) << expt::ErrMsg( error ) << HttpHeader( hdr ) ) ; } return http_code ; } long CurlAgent::Put( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) { Trace("HTTP PUT \"%1%\"", url ) ; Init() ; CURL *curl = m_pimpl->curl ; std::string put_data = data ; // set common options ::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L ) ; ::curl_easy_setopt(curl, CURLOPT_READFUNCTION, &ReadCallback ) ; ::curl_easy_setopt(curl, CURLOPT_READDATA , &put_data ) ; ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, put_data.size() ) ; return ExecCurl( url, dest, hdr ) ; } long CurlAgent::Get( const std::string& url, Receivable *dest, const Header& hdr ) { Trace("HTTP GET \"%1%\"", url ) ; Init() ; // set get specific options ::curl_easy_setopt(m_pimpl->curl, CURLOPT_HTTPGET, 1L); return ExecCurl( url, dest, hdr ) ; } long CurlAgent::Post( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) { Trace("HTTP POST \"%1%\" with \"%2%\"", url, data ) ; Init() ; CURL *curl = m_pimpl->curl ; // make a copy because the parameter is const std::string post_data = data ; // set post specific options ::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() ) ; return ExecCurl( url, dest, hdr ) ; } long CurlAgent::Custom( const std::string& method, const std::string& url, Receivable *dest, const Header& hdr ) { Trace("HTTP %2% \"%1%\"", url, method ) ; CURL *curl = m_pimpl->curl ; ::curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str() ); // ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1 ); return ExecCurl( url, dest, hdr ) ; } void CurlAgent::SetHeader( const Header& hdr ) { // set headers struct curl_slist *curl_hdr = 0 ; for ( Header::iterator i = hdr.begin() ; i != hdr.end() ; ++i ) curl_hdr = curl_slist_append( curl_hdr, i->c_str() ) ; ::curl_easy_setopt( m_pimpl->curl, CURLOPT_HTTPHEADER, curl_hdr ) ; } std::string CurlAgent::RedirLocation() const { return m_pimpl->location ; } std::string CurlAgent::Escape( const std::string& str ) { CURL *curl = m_pimpl->curl ; char *tmp = curl_easy_escape( curl, str.c_str(), str.size() ) ; std::string result = tmp ; curl_free( tmp ) ; return result ; } std::string CurlAgent::Unescape( const std::string& str ) { CURL *curl = m_pimpl->curl ; int r ; char *tmp = curl_easy_unescape( curl, str.c_str(), str.size(), &r ) ; std::string result = tmp ; curl_free( tmp ) ; return result ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/http/CurlAgent.hh000066400000000000000000000041411177605442600220410ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Agent.hh" #include #include namespace gr { namespace http { class Receivable ; /*! \brief agent to provide HTTP access This class provides functions to send HTTP request in many methods (e.g. get, post and put). Normally the HTTP response is returned in a Receivable. */ class CurlAgent : public Agent { public : CurlAgent() ; ~CurlAgent() ; long Put( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) ; long Get( const std::string& url, Receivable *dest, const Header& hdr ) ; long Post( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) ; long Custom( const std::string& method, const std::string& url, Receivable *dest, const Header& hdr ) ; std::string RedirLocation() const ; std::string Escape( const std::string& str ) ; std::string Unescape( const std::string& str ) ; private : static std::size_t HeaderCallback( void *ptr, size_t size, size_t nmemb, CurlAgent *pthis ) ; static std::size_t Receive( void* ptr, size_t size, size_t nmemb, Receivable *recv ) ; void SetHeader( const Header& hdr ) ; long ExecCurl( const std::string& url, Receivable *dest, const Header& hdr ) ; void Init() ; private : struct Impl ; std::auto_ptr m_pimpl ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/http/Download.cc000066400000000000000000000036171177605442600217210ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Download.hh" // #include "util/SignalHandler.hh" #include "Error.hh" #include "util/Crypt.hh" // boost headers #include #include #include #include #include #include #include #include #include #include #include namespace gr { namespace http { Download::Download( const std::string& filename ) : m_file( filename, 0600 ), m_crypt( new crypt::MD5 ) { } Download::Download( const std::string& filename, NoChecksum ) : m_file( filename, 0600 ) { } Download::~Download() { } void Download::Clear() { // no need to do anything } std::string Download::Finish() const { return m_crypt.get() != 0 ? m_crypt->Get() : "" ; } std::size_t Download::OnData( void *data, std::size_t count ) { assert( data != 0 ) ; if ( m_crypt.get() != 0 ) m_crypt->Write( data, count ) ; return m_file.Write( data, count ) ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/http/Download.hh000066400000000000000000000024311177605442600217240ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Receivable.hh" #include "util/StdioFile.hh" #include namespace gr { namespace crypt { class MD5 ; } namespace http { class Download : public http::Receivable { public : struct NoChecksum {} ; Download( const std::string& filename ) ; Download( const std::string& filename, NoChecksum ) ; ~Download() ; std::string Finish() const ; void Clear() ; std::size_t OnData( void *data, std::size_t count ) ; private : StdioFile m_file ; std::auto_ptr m_crypt ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/http/Error.hh000066400000000000000000000025101177605442600212440ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Header.hh" #include "util/Exception.hh" namespace gr { namespace http { struct Error : virtual Exception {} ; // CURL error code typedef boost::error_info CurlCode ; // HTTP response code typedef boost::error_info HttpResponse ; // HTTP response body typedef boost::error_info HttpResponseText ; // URL typedef boost::error_info Url ; // HTTP headers typedef boost::error_info HttpHeader ; } } // end of namespace Grive-grive-93d696a/libgrive/src/http/Header.cc000066400000000000000000000024041177605442600213330ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Header.hh" #include #include #include namespace gr { namespace http { Header::Header() { } void Header::Add( const std::string& str ) { m_vec.push_back( str ) ; } Header::iterator Header::begin() const { return m_vec.begin() ; } Header::iterator Header::end() const { return m_vec.end() ; } std::ostream& operator<<( std::ostream& os, const Header& h ) { std::copy( h.begin(), h.end(), std::ostream_iterator( os, "\n" ) ) ; return os ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/http/Header.hh000066400000000000000000000022611177605442600213460ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include namespace gr { namespace http { class Header { private : typedef std::vector Vec ; public : typedef Vec::const_iterator iterator ; public : Header() ; void Add( const std::string& str ) ; iterator begin() const ; iterator end() const ; private : Vec m_vec ; } ; std::ostream& operator<<( std::ostream& os, const Header& h ) ; }} // end of namespace Grive-grive-93d696a/libgrive/src/http/Receivable.hh000066400000000000000000000017141177605442600222210ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include namespace gr { namespace http { class Receivable { public : virtual std::size_t OnData( void *data, std::size_t count ) = 0 ; virtual void Clear() = 0 ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/http/ResponseLog.cc000066400000000000000000000026671177605442600224160ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ResponseLog.hh" #include "util/DateTime.hh" #include namespace gr { namespace http { ResponseLog::ResponseLog( const std::string& prefix, const std::string& suffix, Receivable *next ) : m_log( Filename(prefix, suffix).c_str() ), m_next( next ) { } std::size_t ResponseLog::OnData( void *data, std::size_t count ) { m_log.rdbuf()->sputn( reinterpret_cast(data), count ) ; return m_next->OnData( data, count ) ; } void ResponseLog::Clear() { assert( m_next != 0 ) ; m_next->Clear() ; } std::string ResponseLog::Filename( const std::string& prefix, const std::string& suffix ) { return prefix + DateTime::Now().Format( "%H%M%S" ) + suffix ; } }} // end of namespace Grive-grive-93d696a/libgrive/src/http/ResponseLog.hh000066400000000000000000000023631177605442600224210ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Receivable.hh" #include #include namespace gr { namespace http { class ResponseLog : public Receivable { public : ResponseLog( const std::string& prefix, const std::string& suffix, Receivable *next ) ; std::size_t OnData( void *data, std::size_t count ) ; void Clear() ; private : static std::string Filename( const std::string& prefix, const std::string& suffix ) ; private : std::ofstream m_log ; Receivable *m_next ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/http/StringResponse.cc000066400000000000000000000021761177605442600231360ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "StringResponse.hh" namespace gr { namespace http { StringResponse::StringResponse() { } void StringResponse::Clear() { m_resp.clear() ; } std::size_t StringResponse::OnData( void *data, std::size_t count ) { m_resp.append( reinterpret_cast(data), count ) ; return count ; } const std::string& StringResponse::Response() const { return m_resp ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/http/StringResponse.hh000066400000000000000000000021041177605442600231370ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Receivable.hh" #include namespace gr { namespace http { class StringResponse : public Receivable { public : StringResponse() ; std::size_t OnData( void *data, std::size_t count ) ; void Clear() ; const std::string& Response() const ; private : std::string m_resp ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/http/XmlResponse.cc000066400000000000000000000024271177605442600224270ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "XmlResponse.hh" #include "xml/Node.hh" #include "xml/TreeBuilder.hh" namespace gr { namespace http { XmlResponse::XmlResponse() : m_tb( new xml::TreeBuilder ) { } std::size_t XmlResponse::OnData( void *data, std::size_t count ) { m_tb->ParseData( reinterpret_cast(data), count ) ; return count ; } void XmlResponse::Clear() { m_tb.reset( new xml::TreeBuilder ) ; } void XmlResponse::Finish() { m_tb->ParseData( 0, 0, true ) ; } xml::Node XmlResponse::Response() const { return m_tb->Result() ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/http/XmlResponse.hh000066400000000000000000000022371177605442600224400ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Receivable.hh" #include namespace gr { namespace xml { class Node ; class TreeBuilder ; } } namespace gr { namespace http { class XmlResponse : public Receivable { public : XmlResponse() ; void Clear() ; std::size_t OnData( void *data, std::size_t count ) ; void Finish() ; xml::Node Response() const ; private : std::auto_ptr m_tb ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/protocol/000077500000000000000000000000001177605442600205165ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/src/protocol/Json.cc000066400000000000000000000177171177605442600217530ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Json.hh" #include "util/StdioFile.hh" #include #include #include #include #include #include namespace gr { Json::Json( ) : m_json( ::json_object_new_object() ) { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json object" ) ) ; } Json::Json( const char *str ) : m_json( ::json_object_new_string( str ) ) { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json string \"" + std::string(str) + "\"" ) ) ; } template <> Json::Json( const std::string& str ) : m_json( ::json_object_new_string( str.c_str() ) ) { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json string \"" + str + "\"" ) ) ; // paranoid check assert( ::json_object_get_string( m_json ) == str ) ; } template <> Json::Json( const int& l ) : m_json( ::json_object_new_int( l ) ) { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json int" ) ) ; } template <> Json::Json( const long& l ) : m_json( ::json_object_new_int( static_cast(l) ) ) { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json int" ) ) ; } template <> Json::Json( const unsigned long& l ) : m_json( ::json_object_new_int( static_cast(l) ) ) { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json int" ) ) ; } template <> Json::Json( const std::vector& arr ) : m_json( ::json_object_new_array( ) ) { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json int" ) ) ; for ( std::vector::const_iterator i = arr.begin() ; i != arr.end() ; ++i ) Add( *i ) ; } template <> Json::Json( const bool& b ) : m_json( ::json_object_new_boolean( b ) ) { if ( m_json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json bool" ) ) ; } Json::Json( struct json_object *json, NotOwned ) : m_json( json ) { assert( m_json != 0 ) ; } Json::Json( struct json_object *json ) : m_json( json ) { assert( json != 0 ) ; ::json_object_get( m_json ) ; } Json::Json( const Json& rhs ) : m_json( rhs.m_json ) { assert( m_json != 0 ) ; ::json_object_get( m_json ) ; } Json::~Json( ) { assert( m_json != 0 ) ; if ( m_json != 0 ) ::json_object_put( m_json ) ; } Json& Json::operator=( const Json& rhs ) { Json tmp( rhs ) ; Swap( tmp ) ; return *this ; } void Json::Swap( Json& other ) { assert( m_json != 0 ) ; assert( other.m_json != 0 ) ; std::swap( m_json, other.m_json ) ; } Json Json::operator[]( const std::string& key ) const { assert( m_json != 0 ) ; struct json_object *j = ::json_object_object_get( m_json, key.c_str() ) ; if ( j == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "key: " + key + " is not found in object" ) << JsonInfo( *this ) ) ; return Json( j ) ; } Json Json::operator[]( const std::size_t& idx ) const { assert( m_json != 0 ) ; struct json_object *j = ::json_object_array_get_idx( m_json, idx ) ; if ( j == 0 ) { std::ostringstream ss ; ss << "index " << idx << " is not found in array" ; BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( ss.str() ) << JsonInfo( *this ) ) ; } return Json( j ) ; } bool Json::Has( const std::string& key ) const { assert( m_json != 0 ) ; return ::json_object_object_get( m_json, key.c_str() ) != 0 ; } bool Json::Get( const std::string& key, Json& json ) const { assert( m_json != 0 ) ; struct json_object *j = ::json_object_object_get( m_json, key.c_str() ) ; if ( j != 0 ) { Json tmp( j, NotOwned() ) ; json.Swap( tmp ) ; return true ; } else return false ; } void Json::Add( const std::string& key, const Json& json ) { assert( m_json != 0 ) ; assert( json.m_json != 0 ) ; ::json_object_get( json.m_json ) ; ::json_object_object_add( m_json, key.c_str(), json.m_json ) ; } void Json::Add( const Json& json ) { assert( m_json != 0 ) ; assert( json.m_json != 0 ) ; ::json_object_get( json.m_json ) ; ::json_object_array_add( m_json, json.m_json ) ; } bool Json::Bool() const { assert( m_json != 0 ) ; return ::json_object_get_boolean( m_json ) ; } template <> bool Json::Is() const { assert( m_json != 0 ) ; return ::json_object_is_type( m_json, json_type_boolean ) ; } std::string Json::Str() const { assert( m_json != 0 ) ; return ::json_object_get_string( m_json ) ; } template <> bool Json::Is() const { assert( m_json != 0 ) ; return ::json_object_is_type( m_json, json_type_string ) ; } int Json::Int() const { assert( m_json != 0 ) ; return ::json_object_get_int( m_json ) ; } template <> bool Json::Is() const { assert( m_json != 0 ) ; return ::json_object_is_type( m_json, json_type_int ) ; } std::ostream& operator<<( std::ostream& os, const Json& json ) { assert( json.m_json != 0 ) ; return os << ::json_object_to_json_string( json.m_json ) ; } void Json::Write( StdioFile& file ) const { const char *str = ::json_object_to_json_string( m_json ) ; file.Write( str, std::strlen(str) ) ; } Json::Type Json::DataType() const { assert( m_json != 0 ) ; return static_cast( ::json_object_get_type( m_json ) ) ; } Json::Object Json::AsObject() const { Object result ; json_object_object_foreach( m_json, key, val ) { result.insert( Object::value_type( key, Json( val ) ) ) ; } return result ; } template <> bool Json::Is() const { assert( m_json != 0 ) ; return ::json_object_is_type( m_json, json_type_object ) ; } Json::Array Json::AsArray() const { std::size_t count = ::json_object_array_length( m_json ) ; Array result ; for ( std::size_t i = 0 ; i < count ; ++i ) result.push_back( Json( ::json_object_array_get_idx( m_json, i ) ) ) ; return result ; } template <> bool Json::Is() const { assert( m_json != 0 ) ; return ::json_object_is_type( m_json, json_type_array ) ; } Json Json::FindInArray( const std::string& key, const std::string& value ) const { std::size_t count = ::json_object_array_length( m_json ) ; for ( std::size_t i = 0 ; i < count ; ++i ) { Json item( ::json_object_array_get_idx( m_json, i ) ) ; if ( item.Has(key) && item[key].Str() == value ) return item ; } BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot find " + key + " = " + value + " in array" ) ) ; } bool Json::FindInArray( const std::string& key, const std::string& value, Json& result ) const { try { result = FindInArray( key, value ) ; return true ; } catch ( Error& ) { return false ; } } Json Json::Parse( const std::string& str ) { struct json_object *json = ::json_tokener_parse( str.c_str() ) ; if ( json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "json parse error" ) ) ; return Json( json, NotOwned() ) ; } Json Json::ParseFile( const std::string& filename ) { StdioFile file( filename ) ; struct json_tokener *tok = ::json_tokener_new() ; struct json_object *json = 0 ; char buf[1024] ; std::size_t count = 0 ; while ( (count = file.Read( buf, sizeof(buf) ) ) > 0 ) json = ::json_tokener_parse_ex( tok, buf, count ) ; if ( json == 0 ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( ::json_tokener_errors[tok->err] ) ) ; ::json_tokener_free( tok ) ; return Json( json, NotOwned() ) ; } } Grive-grive-93d696a/libgrive/src/protocol/Json.hh000066400000000000000000000047021177605442600217530ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "util/Exception.hh" #include #include #include struct json_object ; namespace gr { class StdioFile ; class Json { public : typedef std::map Object ; typedef std::vector Array ; struct Error : virtual Exception {} ; typedef boost::error_info JsonInfo ; public : template explicit Json( const T& val ) ; Json() ; Json( const Json& rhs ) ; Json( const char *str ) ; ~Json( ) ; static Json Parse( const std::string& str ) ; static Json ParseFile( const std::string& filename ) ; Json operator[]( const std::string& key ) const ; Json operator[]( const std::size_t& idx ) const ; Json& operator=( const Json& rhs ) ; void Swap( Json& other ) ; std::string Str() const ; int Int() const ; double Double() const ; bool Bool() const ; Array AsArray() const ; Object AsObject() const ; template bool Is() const ; bool Has( const std::string& key ) const ; bool Get( const std::string& key, Json& json ) const ; void Add( const std::string& key, const Json& json ) ; void Add( const Json& json ) ; Json FindInArray( const std::string& key, const std::string& value ) const ; bool FindInArray( const std::string& key, const std::string& value, Json& result ) const ; friend std::ostream& operator<<( std::ostream& os, const Json& json ) ; void Write( StdioFile& file ) const ; enum Type { null_type, bool_type, double_type, int_type, object_type, array_type, string_type } ; Type DataType() const ; private : Json( struct json_object *json ) ; struct NotOwned {} ; Json( struct json_object *json, NotOwned ) ; private : public : struct json_object *m_json ; } ; }Grive-grive-93d696a/libgrive/src/protocol/JsonResponse.cc000066400000000000000000000021711177605442600234560ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "JsonResponse.hh" #include "protocol/Json.hh" namespace gr { namespace http { JsonResponse::JsonResponse() { } void JsonResponse::Clear() { m_resp.Clear() ; } std::size_t JsonResponse::OnData( void *data, std::size_t count ) { return m_resp.OnData( data, count ) ; } Json JsonResponse::Response() const { return Json::Parse( m_resp.Response() ) ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/protocol/JsonResponse.hh000066400000000000000000000021511177605442600234660ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "http/Receivable.hh" #include "http/StringResponse.hh" namespace gr { class Json ; } namespace gr { namespace http { class JsonResponse : public Receivable { public : JsonResponse() ; std::size_t OnData( void *data, std::size_t count ) ; void Clear() ; Json Response() const ; private : StringResponse m_resp ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/protocol/OAuth2.cc000066400000000000000000000061651177605442600221370ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "OAuth2.hh" #include "JsonResponse.hh" #include "Json.hh" #include "http/CurlAgent.hh" #include "http/Header.hh" #include "util/log/Log.hh" // for debugging #include namespace gr { const std::string token_url = "https://accounts.google.com/o/oauth2/token" ; OAuth2::OAuth2( const std::string& refresh_code, const std::string& client_id, const std::string& client_secret ) : m_refresh( refresh_code ), m_client_id( client_id ), m_client_secret( client_secret ) { Refresh( ) ; } OAuth2::OAuth2( const std::string& client_id, const std::string& client_secret ) : m_client_id( client_id ), m_client_secret( client_secret ) { } void OAuth2::Auth( const std::string& auth_code ) { std::string post = "code=" + auth_code + "&client_id=" + m_client_id + "&client_secret=" + m_client_secret + "&redirect_uri=" + "urn:ietf:wg:oauth:2.0:oob" + "&grant_type=authorization_code" ; http::JsonResponse resp ; http::CurlAgent http ; DisableLog dlog( log::debug ) ; http.Post( token_url, post, &resp, http::Header() ) ; Json jresp = resp.Response() ; m_access = jresp["access_token"].Str() ; m_refresh = jresp["refresh_token"].Str() ; } std::string OAuth2::MakeAuthURL( const std::string& client_id, const std::string& state ) { http::CurlAgent h ; return "https://accounts.google.com/o/oauth2/auth" "?scope=" + h.Escape( "https://www.googleapis.com/auth/userinfo.email" ) + "+" + h.Escape( "https://www.googleapis.com/auth/userinfo.profile" ) + "+" + h.Escape( "https://docs.google.com/feeds/" ) + "+" + h.Escape( "https://docs.googleusercontent.com/" ) + "+" + h.Escape( "https://spreadsheets.google.com/feeds/" ) + "&redirect_uri=urn:ietf:wg:oauth:2.0:oob" "&response_type=code" "&client_id=" + client_id ; } void OAuth2::Refresh( ) { std::string post = "refresh_token=" + m_refresh + "&client_id=" + m_client_id + "&client_secret=" + m_client_secret + "&grant_type=refresh_token" ; http::JsonResponse resp ; http::CurlAgent http ; DisableLog dlog( log::debug ) ; http.Post( token_url, post, &resp, http::Header() ) ; m_access = resp.Response()["access_token"].Str() ; } std::string OAuth2::RefreshToken( ) const { return m_refresh ; } std::string OAuth2::AccessToken( ) const { return m_access ; } std::string OAuth2::HttpHeader( ) const { return "Authorization: Bearer " + m_access ; } } // end of namespace Grive-grive-93d696a/libgrive/src/protocol/OAuth2.hh000066400000000000000000000027721177605442600221510ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include namespace gr { class OAuth2 { public : OAuth2( const std::string& client_id, const std::string& client_secret ) ; OAuth2( const std::string& refresh_code, const std::string& client_id, const std::string& client_secret ) ; std::string Str() const ; static std::string MakeAuthURL( const std::string& client_id, const std::string& state = std::string() ) ; void Auth( const std::string& auth_code ) ; void Refresh( ) ; std::string RefreshToken( ) const ; std::string AccessToken( ) const ; // adding HTTP auth header std::string HttpHeader( ) const ; private : std::string m_access ; std::string m_refresh ; const std::string m_client_id ; const std::string m_client_secret ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/util/000077500000000000000000000000001177605442600176325ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/src/util/CArray.hh000066400000000000000000000037401177605442600213400ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include namespace gr { /*! \brief get the begin iterator from an array \internal This function returns the begin "iterator" of an array. It is useful to treat an array like an STL container. For example: \code int array[10] = { 1, 2, 3, 4, 5 } ; std::vector v ; std::copy( Begin(array), End(array), std::back_inserter( v ) ; \endcode \param array reference to the array \return the begin iterator of the array. i.e. \a array itself \sa End(), Count() */ template T* Begin( T (&array)[n] ) { return array ; } /*! \brief get the end iterator from an array \internal This function returns the end "iterator" of an array. It is useful to treat an array like an STL container. \param array reference to the array \return the end iterator of the array. i.e. \a array+n \sa Begin(), Count() */ template T* End( T (&array)[n] ) { return array + n ; } /*! \brief get the number of elements in the array \internal This function will return the number of elements in the array. \return the number of elements in the array \sa Begin(), End() */ template std::size_t Count( T (&array)[n] ) { return n ; } } // end of namespace Grive-grive-93d696a/libgrive/src/util/Crypt.cc000066400000000000000000000042401177605442600212420ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Crypt.hh" #include "StdioFile.hh" #include "Exception.hh" #include #include // dependent libraries #include #include namespace gr { namespace crypt { const std::size_t read_size = 8 * 1024 ; struct MD5::Impl { gcry_md_hd_t hd ; } ; MD5::MD5() : m_impl( new Impl ) { ::gcry_error_t err = ::gcry_md_open( &m_impl->hd, GCRY_MD_MD5, 0 ) ; if ( err != GPG_ERR_NO_ERROR ) { BOOST_THROW_EXCEPTION( Exception() << expt::ErrMsg( ::gcry_strerror(err) ) ) ; } } MD5::~MD5() { ::gcry_md_close( m_impl->hd ) ; } void MD5::Write( const void *data, std::size_t size ) { ::gcry_md_write( m_impl->hd, data, size ) ; } std::string MD5::Get() const { unsigned char *md5 = ::gcry_md_read( m_impl->hd, GCRY_MD_MD5 ) ; unsigned int len = ::gcry_md_get_algo_dlen(GCRY_MD_MD5) ; // format the MD5 string std::ostringstream ss ; for ( unsigned int i = 0 ; i < len ; i++ ) ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(md5[i]) ; return ss.str() ; } std::string MD5::Get( const fs::path& file ) { try { StdioFile sfile( file ) ; return Get( sfile ) ; } catch ( StdioFile::Error& ) { return "" ; } } std::string MD5::Get( StdioFile& file ) { char buf[read_size] ; MD5 crypt ; std::size_t count = 0 ; while ( (count = file.Read( buf, sizeof(buf) )) > 0 ) crypt.Write( buf, count ) ; return crypt.Get() ; } } } // end of namespaces Grive-grive-93d696a/libgrive/src/util/Crypt.hh000066400000000000000000000022731177605442600212600ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include namespace gr { class StdioFile ; namespace crypt { class MD5 { public : MD5() ; ~MD5() ; static std::string Get( StdioFile& file ) ; static std::string Get( const boost::filesystem::path& file ) ; void Write( const void *data, std::size_t size ) ; std::string Get() const ; private : struct Impl ; std::auto_ptr m_impl ; } ; } } // end of namespace gr Grive-grive-93d696a/libgrive/src/util/DateTime.cc000066400000000000000000000077151177605442600216470ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "DateTime.hh" #include "Exception.hh" // boost headers #include #include #include #include #include #include #include #include #include #include #include #include namespace gr { DateTime::DateTime( ) : m_sec ( 0 ), m_nsec ( 0 ) { } DateTime::DateTime( const std::string& iso ) : m_sec ( 0 ), m_nsec ( 0 ) { struct tm tp = {} ; const char *r = ::strptime( iso.c_str(), "%Y-%m-%dT%H:%M:%S", &tp ) ; // should be '.' followed by 3 digits and 'Z' (e.g. .123Z) if ( r != 0 && r - iso.c_str() == 19 ) { m_sec = ::timegm( &tp ) ; // at least 3 digits is OK. we don't care the Z if ( *r == '.' && ::strlen( r+1 ) >= 3 ) m_nsec = std::atoi( r+1 ) * 1000 * 1000 ; } } DateTime::DateTime( std::time_t sec, unsigned long nsec ) { Assign( sec, nsec ) ; } void DateTime::Assign( std::time_t sec, unsigned long nsec ) { m_sec = sec + nsec / 1000000000 ; m_nsec = nsec % 1000000000 ; } DateTime DateTime::Now() { struct timeval tv = {} ; if ( ::gettimeofday( &tv, 0 ) != 0 ) { BOOST_THROW_EXCEPTION( Exception() << boost::errinfo_api_function("gettimeofday") << boost::errinfo_errno(errno) ) ; } return DateTime( tv.tv_sec, tv.tv_usec * 1000 ) ; } std::string DateTime::Format( const std::string& format ) const { struct tm tp = Tm() ; char tmp[1024] ; std::size_t count = ::strftime( tmp, sizeof(tmp), format.c_str(), &tp ) ; return count > 0 ? std::string( tmp, count ) : "" ; } struct tm DateTime::Tm() const { struct tm tp ; gmtime_r( &m_sec, &tp ) ; return tp ; } std::time_t DateTime::Sec( ) const { return m_sec ; } unsigned long DateTime::NanoSec( ) const { assert( m_nsec < 1000000000 ) ; return m_nsec ; } std::ostream& operator<<( std::ostream& os, const DateTime& dt ) { struct tm tp = dt.Tm() ; char buf[40] ; strftime( buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tp ) ; return os << buf << '.' << std::setw( 3 ) << std::setfill('0') << dt.NanoSec()/1000000 << 'Z' ; } struct timeval DateTime::Tv() const { assert( m_nsec < 1000000000 ) ; timeval result ; result.tv_sec = m_sec ; result.tv_usec = m_nsec / 1000 ; return result ; } bool DateTime::operator==( const DateTime& dt ) const { assert( m_nsec < 1000000000 ) ; return m_sec == dt.m_sec && m_nsec == dt.m_nsec ; } bool DateTime::operator!=( const DateTime& dt ) const { return !( *this == dt ) ; } bool DateTime::operator>( const DateTime& dt ) const { assert( m_nsec < 1000000000 ) ; assert( dt.m_nsec < 1000000000 ) ; return m_sec == dt.m_sec ? m_nsec > dt.m_nsec : m_sec > dt.m_sec ; } bool DateTime::operator>=( const DateTime& dt ) const { return ( *this > dt ) || ( *this == dt ) ; } bool DateTime::operator<( const DateTime& dt ) const { return !( *this >= dt ) ; } bool DateTime::operator<=( const DateTime& dt ) const { return !( *this > dt ) ; } void DateTime::Swap( DateTime& dt ) { std::swap( m_sec, dt.m_sec ) ; std::swap( m_nsec, dt.m_nsec ) ; } std::string DateTime::ToString() const { std::ostringstream ss ; ss << *this ; return ss.str() ; } } // end of namespace Grive-grive-93d696a/libgrive/src/util/DateTime.hh000066400000000000000000000033361177605442600216540ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include #include namespace gr { class DateTime { public : DateTime( ) ; explicit DateTime( const std::string& iso ) ; explicit DateTime( std::time_t sec, unsigned long nsec = 0 ) ; void Assign( std::time_t sec, unsigned long nsec = 0 ) ; static DateTime Now() ; std::time_t Sec( ) const ; unsigned long NanoSec( ) const ; std::string Format( const std::string& format ) const ; tm Tm() const ; timeval Tv() const ; bool operator==( const DateTime& dt ) const ; bool operator!=( const DateTime& dt ) const ; bool operator>( const DateTime& dt ) const ; bool operator>=( const DateTime& dt ) const ; bool operator<( const DateTime& dt ) const ; bool operator<=( const DateTime& dt ) const ; void Swap( DateTime& dt ) ; std::string ToString() const ; private : std::time_t m_sec ; unsigned long m_nsec ; } ; std::ostream& operator<<( std::ostream& os, const DateTime& dt ) ; } // end of namespace Grive-grive-93d696a/libgrive/src/util/Destroy.hh000066400000000000000000000016041177605442600216050ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once namespace gr { struct Destroy { template void operator()( T *t ) const { delete t ; } } ; } // end of namespace Grive-grive-93d696a/libgrive/src/util/Exception.cc000066400000000000000000000020771177605442600221050ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "util/Exception.hh" #include "bfd/Backtrace.hh" #include "bfd/Debug.hh" #include #include #include #include namespace gr { class Backtrace ; Exception::Exception( ) { #ifdef HAVE_BFD *this << expt::BacktraceInfo( Backtrace() ) ; #endif } } // end of namespace Grive-grive-93d696a/libgrive/src/util/Exception.hh000066400000000000000000000041531177605442600221140ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include #include namespace gr { class Backtrace ; /** \defgroup exception Exception Classes */ /// base class for exception in libpdfdoc /** \ingroup exception This class is the base class for all exception class in libpdfdoc. */ struct Exception : virtual public std::exception, virtual public boost::exception { Exception( ) ; } ; struct FileError : virtual Exception {} ; /// Parse error exception. /** \ingroup exception This exception will be thrown when there is a parse error when reading a PDF file. */ struct ParseError : virtual Exception {} ; /// Invalid type exception. /** \ingroup exception This exception will be thrown when the Object cannot convert its underlying data to a specific type. The what() member function will describe the expected and actual type of the data. */ struct BadType : virtual Exception {} ; struct Unsupported : virtual Exception {} ; // Exception informations namespace expt { // back-trace information. should be present for all exceptions typedef boost::error_info BacktraceInfo ; // generic error message typedef boost::error_info ErrMsg ; // nested exception typedef boost::error_info Nested ; } } // end of namespace Grive-grive-93d696a/libgrive/src/util/FileSystem.hh000066400000000000000000000022241177605442600222370ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #define BOOST_FILESYSTEM_VERSION 3 #include namespace gr { namespace fs = boost::filesystem ; // these two functions are for ancient distro which does not have boost v1.44 or later // will be removed once people upgrade inline std::string Path2Str( const fs::path& p ) { return p.string() ; } inline std::string Path2Str( const std::string& s ) { return s ; } } Grive-grive-93d696a/libgrive/src/util/Function.hh000066400000000000000000000076451177605442600217540ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace gr { namespace impl { template class FuncImpl ; template class FuncImpl { public : virtual R operator()( ) = 0 ; virtual FuncImpl* Clone() const = 0 ; virtual ~FuncImpl() {} } ; template class FuncImpl { public : virtual R operator()(P1) = 0 ; virtual FuncImpl* Clone() const = 0 ; virtual ~FuncImpl() {} } ; template class FuncImpl { public : virtual R operator()(P1,P2) = 0 ; virtual FuncImpl* Clone() const = 0 ; virtual ~FuncImpl() {} } ; template struct FuncTrait ; struct NullType {} ; template struct FuncTrait { typedef R ReturnType ; typedef NullType Param1Type ; typedef NullType Param2Type ; } ; template struct FuncTrait { typedef R ReturnType ; typedef P1 Param1Type ; typedef NullType Param2Type ; } ; template struct FuncTrait { typedef R ReturnType ; typedef P1 Param1Type ; typedef P2 Param2Type ; } ; template class FuncHolder : public FuncImpl { public : explicit FuncHolder( const F& f ) : m_func( f ) { } FuncHolder* Clone() const { return new FuncHolder( *this ) ; } typedef typename FuncTrait::ReturnType ReturnType ; ReturnType operator()() { return m_func(); } ReturnType operator()( typename FuncTrait::Param1Type p1) { return m_func(p1); } ReturnType operator()( typename FuncTrait::Param1Type p1, typename FuncTrait::Param2Type p2) { return m_func(p1,p2); } private : F m_func ; } ; template struct NullFunc { typedef typename FuncTrait::ReturnType ReturnType ; ReturnType operator()() { return ReturnType() ; } ReturnType operator()( typename FuncTrait::Param1Type p1) { return ReturnType() ; } ReturnType operator()( typename FuncTrait::Param1Type p1, typename FuncTrait::Param2Type p2) { return ReturnType() ; } } ; template FuncHolder* MakeFuncHolder( F func ) { return new FuncHolder( func ) ; } } template class Function { public : Function( ) : m_pimpl( impl::MakeFuncHolder( impl::NullFunc() ) ) { } Function( const Function& f ) : m_pimpl( f.m_pimpl->Clone() ) { } template Function( const F& f ) : m_pimpl( impl::MakeFuncHolder( f ) ) { } Function& operator=( const Function& f ) { Function tmp( f ) ; std::swap( m_pimpl, tmp.m_pimpl ) ; return *this ; } ~Function( ) { } typedef typename impl::FuncTrait::ReturnType ReturnType ; ReturnType operator()( ) { return (*m_pimpl)() ; } template ReturnType operator()( P1 p1 ) { return (*m_pimpl)( p1 ) ; } template ReturnType operator()( P1 p1, P2 p2 ) { return (*m_pimpl)( p1, p2 ) ; } ; private : typedef impl::FuncImpl Impl ; std::auto_ptr m_pimpl ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/util/OS.cc000066400000000000000000000044471177605442600204730ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "OS.hh" #include "DateTime.hh" #include "Exception.hh" // boost headers #include #include #include #include #include #include #include // OS specific headers #include #include #include #include namespace gr { namespace os { DateTime FileCTime( const fs::path& filename ) { return FileCTime( filename.string() ) ; } DateTime FileCTime( const std::string& filename ) { struct stat s = {} ; if ( ::stat( filename.c_str(), &s ) != 0 ) { BOOST_THROW_EXCEPTION( Error() << boost::errinfo_api_function("stat") << boost::errinfo_errno(errno) << boost::errinfo_file_name(filename) ) ; } #if defined __APPLE__ && defined __DARWIN_64_BIT_INO_T return DateTime( s.st_ctimespec.tv_sec, s.st_ctimespec.tv_nsec ) ; #else return DateTime( s.st_ctim.tv_sec, s.st_ctim.tv_nsec); #endif } void SetFileTime( const fs::path& filename, const DateTime& t ) { return SetFileTime( filename.string(), t ) ; } void SetFileTime( const std::string& filename, const DateTime& t ) { struct timeval tvp[2] = { t.Tv(), t.Tv() } ; if ( ::utimes( filename.c_str(), tvp ) != 0 ) BOOST_THROW_EXCEPTION( Error() << boost::errinfo_api_function("utimes") << boost::errinfo_errno(errno) << boost::errinfo_file_name(filename) ) ; } } } // end of namespaces Grive-grive-93d696a/libgrive/src/util/OS.hh000066400000000000000000000022671177605442600205030ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Exception.hh" #include "FileSystem.hh" #include namespace gr { class DateTime ; class Path ; namespace os { struct Error : virtual Exception {} ; DateTime FileCTime( const std::string& filename ) ; DateTime FileCTime( const fs::path& filename ) ; void SetFileTime( const std::string& filename, const DateTime& t ) ; void SetFileTime( const fs::path& filename, const DateTime& t ) ; } } // end of namespaces Grive-grive-93d696a/libgrive/src/util/SignalHandler.cc000066400000000000000000000042211177605442600226530ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "SignalHandler.hh" #include #include #include #include #include namespace gr { SignalError::SignalError( const std::string& message ) : std::runtime_error( message ) { } SignalError::~SignalError() throw () { } SignalHandler::SignalHandler() { } SignalHandler::SignalHandler( const SignalHandler& right ) { } SignalHandler& SignalHandler::operator ==( const SignalHandler& right ) { return (*this); } SignalHandler::~SignalHandler() { } SignalHandler& SignalHandler::GetInstance() { static SignalHandler _instance; return _instance; } void SignalHandler::UnregisterSignal( unsigned int signumber ) { m_signals[signumber] = 0 ; // Restore the old signal signal( ( int ) signumber, m_signalsOld[signumber] ); } void SignalHandler::RegisterSignal( unsigned int signumber, Callback callback ) { signals_t::const_iterator anIterator ; for (anIterator = m_signals.begin(); anIterator != m_signals.end(); ++anIterator) { if (anIterator->first == signumber) { if (anIterator->second != 0) { std::ostringstream oss; oss << "Signal " << signumber << " already has a callback!"; throw SignalError( oss.str() ); ; } } } m_signals[signumber] = callback ; if ( ( m_signalsOld[signumber] = signal( ( int ) signumber, m_signals[signumber] ) ) == SIG_ERR ) { throw SignalError( " Error while registering the signal! " ) ; } } } Grive-grive-93d696a/libgrive/src/util/SignalHandler.hh000066400000000000000000000030731177605442600226710ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include namespace gr { class SignalError : public std::runtime_error { public : SignalError( const std::string& message ) ; virtual ~SignalError() throw () ; }; class SignalFunctor { public : SignalFunctor() ; virtual ~SignalFunctor() ; static void Callback( int signumber ) ; }; class SignalHandler { typedef void (*Callback)(int); typedef std::map signals_t ; public : virtual ~SignalHandler() ; void RegisterSignal ( unsigned int signumber, Callback callback ) ; void UnregisterSignal( unsigned int signumber ); static SignalHandler& GetInstance() ; private : SignalHandler() ; SignalHandler( const SignalHandler& right ) ; SignalHandler& operator==( const SignalHandler& right ) ; signals_t m_signals; signals_t m_signalsOld; }; } Grive-grive-93d696a/libgrive/src/util/StdioFile.cc000066400000000000000000000063121177605442600220250ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "StdioFile.hh" #include // boost headers #include #include #include #include #include #include #include #include #include #include namespace gr { StdioFile::StdioFile( ) : m_fd( -1 ) { } StdioFile::StdioFile( const fs::path& path ) : m_fd( -1 ) { OpenForRead( path ) ; } StdioFile::StdioFile( const fs::path& path, int mode ) : m_fd( -1 ) { OpenForWrite( path, mode ) ; } StdioFile::~StdioFile( ) { Close() ; } void StdioFile::Open( const fs::path& path, int flags, int mode ) { if ( IsOpened() ) Close() ; assert( m_fd == -1 ) ; m_fd = ::open( path.string().c_str(), flags, mode ) ; if ( m_fd == -1 ) { BOOST_THROW_EXCEPTION( Error() << boost::errinfo_api_function("open") << boost::errinfo_errno(errno) << boost::errinfo_file_name(path.string()) ) ; } } void StdioFile::OpenForRead( const fs::path& path ) { Open( path, O_RDONLY, 0 ) ; } void StdioFile::OpenForWrite( const fs::path& path, int mode ) { Open( path, O_CREAT|O_RDWR|O_TRUNC, mode ) ; } void StdioFile::Close() { if ( IsOpened() ) { close( m_fd ) ; m_fd = -1 ; } } bool StdioFile::IsOpened() const { return m_fd != -1 ; } std::size_t StdioFile::Read( void *ptr, std::size_t size ) { assert( IsOpened() ) ; ssize_t count = ::read( m_fd, ptr, size ) ; if ( count == -1 ) { BOOST_THROW_EXCEPTION( Error() << boost::errinfo_api_function("read") << boost::errinfo_errno(errno) ) ; } return count ; } std::size_t StdioFile::Write( const void *ptr, std::size_t size ) { assert( IsOpened() ) ; ssize_t count = ::write( m_fd, ptr, size ) ; if ( count == -1 ) { BOOST_THROW_EXCEPTION( Error() << boost::errinfo_api_function("read") << boost::errinfo_errno(errno) ) ; } return count ; } long StdioFile::Seek( long offset, int whence ) { assert( IsOpened() ) ; return ::lseek( m_fd, offset, whence ) ; } long StdioFile::Tell() const { assert( IsOpened() ) ; return ::lseek( m_fd, 0, SEEK_CUR ) ; } void StdioFile::Chmod( int mode ) { assert( IsOpened() ) ; if ( ::fchmod( m_fd, mode ) != 0 ) { BOOST_THROW_EXCEPTION( Error() << boost::errinfo_api_function("fchmod") << boost::errinfo_errno(errno) ) ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/util/StdioFile.hh000066400000000000000000000027521177605442600220430ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Exception.hh" #include "FileSystem.hh" #include namespace gr { class StdioFile { public : struct Error : virtual Exception {} ; public : StdioFile() ; StdioFile( const fs::path& path ) ; StdioFile( const fs::path& path, int mode ) ; ~StdioFile( ) ; void OpenForRead( const fs::path& path ) ; void OpenForWrite( const fs::path& path, int mode = 0600 ) ; void Close() ; bool IsOpened() const ; std::size_t Read( void *ptr, std::size_t size ) ; std::size_t Write( const void *ptr, std::size_t size ) ; long Seek( long offset, int whence ) ; long Tell() const ; void Chmod( int mode ) ; private : void Open( const fs::path& path, int flags, int mode ) ; private : int m_fd ; } ; } // end of namespace Grive-grive-93d696a/libgrive/src/util/log/000077500000000000000000000000001177605442600204135ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/src/util/log/CommonLog.cc000066400000000000000000000025351177605442600226210ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "CommonLog.hh" namespace gr { namespace log { CommonLog::CommonLog() { m_enabled[log::debug] = false ; m_enabled[log::verbose] = false ; m_enabled[log::info] = true ; m_enabled[log::warning] = true ; m_enabled[log::error] = true ; m_enabled[log::critical] = true ; } bool CommonLog::Enable( log::Serverity s, bool enable ) { assert( s >= debug && s < serverity_count ) ; bool prev = m_enabled[s] ; m_enabled[s] = enable ; return prev ; } bool CommonLog::IsEnabled( log::Serverity s ) const { assert( s >= debug && s < serverity_count ) ; return m_enabled[s] ; } }} // end of namespace Grive-grive-93d696a/libgrive/src/util/log/CommonLog.hh000066400000000000000000000020701177605442600226250ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Log.hh" #include namespace gr { namespace log { class CommonLog : public LogBase { public : CommonLog() ; bool Enable( log::Serverity s, bool enable = true ) ; bool IsEnabled( log::Serverity s ) const ; private : std::bitset m_enabled ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/util/log/CompositeLog.cc000066400000000000000000000030041177605442600233230ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "CompositeLog.hh" #include #include "util/Destroy.hh" namespace gr { namespace log { CompositeLog::CompositeLog() { Enable(log::debug, true) ; Enable(log::verbose, true) ; Enable(log::info, true) ; Enable(log::warning, true) ; Enable(log::error, true) ; Enable(log::critical, true) ; } CompositeLog::~CompositeLog() { std::for_each( m_logs.begin(), m_logs.end(), Destroy() ) ; } LogBase* CompositeLog::Add( std::auto_ptr log ) { m_logs.push_back( log.get() ) ; return log.release() ; } void CompositeLog::Log( const log::Fmt& msg, log::Serverity s ) { for ( std::vector::iterator i = m_logs.begin(); i != m_logs.end(); ++i ) { if ( IsEnabled(s) && (*i)->IsEnabled(s) ) (*i)->Log( msg, s ) ; } } } } // end of namespace Grive-grive-93d696a/libgrive/src/util/log/CompositeLog.hh000066400000000000000000000021421177605442600233370ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "CommonLog.hh" #include #include namespace gr { namespace log { class CompositeLog : public CommonLog { public : CompositeLog() ; ~CompositeLog() ; LogBase* Add( std::auto_ptr log ) ; void Log( const log::Fmt& msg, log::Serverity s ) ; private : std::vector m_logs ; } ; }} // end of namespace Grive-grive-93d696a/libgrive/src/util/log/DefaultLog.cc000066400000000000000000000025171177605442600227550ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "DefaultLog.hh" #include #include namespace gr { namespace log { DefaultLog::DefaultLog() : m_log( std::cerr ) { // Enable(log::debug, true) ; // Enable(log::verbose, true) ; } DefaultLog::DefaultLog( const std::string& filename ) : m_file( filename.c_str() ), m_log( m_file ) { } void DefaultLog::Log( const log::Fmt& msg, log::Serverity s ) { if ( IsEnabled(s) ) { switch ( s ) { case log::debug: case log::info: m_log << msg << std::endl ; break ; default: m_log << msg << std::endl ; break ; } } } } } // end of namespace Grive-grive-93d696a/libgrive/src/util/log/DefaultLog.hh000066400000000000000000000021411177605442600227600ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "CommonLog.hh" #include #include namespace gr { namespace log { class DefaultLog : public CommonLog { public : DefaultLog() ; explicit DefaultLog( const std::string& filename ) ; void Log( const log::Fmt& msg, log::Serverity s ) ; private : std::ofstream m_file ; std::ostream& m_log ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/src/util/log/Log.cc000066400000000000000000000032371177605442600214500ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Log.hh" #include namespace gr { class MockLog : public LogBase { public : void Log( const log::Fmt&, log::Serverity ) { } bool Enable( log::Serverity, bool enable ) { return enable ; } bool IsEnabled( log::Serverity ) const { return true ; } } ; LogBase* LogBase::Inst( std::auto_ptr log ) { static std::auto_ptr inst( new MockLog ) ; if ( log.get() != 0 ) inst = log ; assert( inst.get() != 0 ) ; return inst.get() ; } LogBase::LogBase() { } LogBase::~LogBase() { } void Log( const std::string& str, log::Serverity s ) { LogBase::Inst()->Log( log::Fmt(str), s ) ; } void Trace( const std::string& str ) { LogBase::Inst()->Log( log::Fmt(str), log::debug ) ; } DisableLog::DisableLog( log::Serverity s ) : m_sev( s ), m_prev( LogBase::Inst()->Enable( s, false ) ) { } DisableLog::~DisableLog() { LogBase::Inst()->Enable( m_sev, m_prev ) ; } } // end of namespace Grive-grive-93d696a/libgrive/src/util/log/Log.hh000066400000000000000000000065721177605442600214670ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace gr { namespace log { /// defines the types of the log message enum Serverity { /// user unfriendly messages. only meant for developers. debug, /// enabled only if -V is specified. grive tries to tell you every /// single thing it tries to do. verbose, /// notification messages indicates nothing is going wrong info, /// potential error messages warning, /// an error has occurs but grive doesn't need to quit error, /// grive cannot proceed critical, /// must be put at the end, equal to number of serverities serverity_count } ; typedef boost::format Fmt ; } /*! \brief Base class and singleton of log facilities */ class LogBase { public : virtual void Log( const log::Fmt& msg, log::Serverity s = log::info ) = 0 ; virtual bool Enable( log::Serverity s, bool enable = true ) = 0 ; virtual bool IsEnabled( log::Serverity s ) const = 0 ; static LogBase* Inst( std::auto_ptr log = std::auto_ptr() ) ; ~LogBase() ; protected : LogBase() ; } ; class DisableLog { public : DisableLog( log::Serverity s ) ; ~DisableLog() ; private : log::Serverity m_sev ; bool m_prev ; } ; void Log( const std::string& str, log::Serverity s = log::info ) ; template void Log( const std::string& fmt, const P1& p1, log::Serverity s = log::info ) { LogBase::Inst()->Log( log::Fmt(fmt) % p1, s ) ; } template void Log( const std::string& fmt, const P1& p1, const P2& p2, log::Serverity s = log::info ) { LogBase::Inst()->Log( log::Fmt(fmt) % p1 % p2, s ) ; } template void Log( const std::string& fmt, const P1& p1, const P2& p2, const P3& p3, log::Serverity s = log::info ) { LogBase::Inst()->Log( log::Fmt(fmt) % p1 % p2 % p3, s ) ; } template void Log( const std::string& fmt, const P1& p1, const P2& p2, const P3& p3, const P4& p4, log::Serverity s = log::info ) { LogBase::Inst()->Log( log::Fmt(fmt) % p1 % p2 % p3 % p4, s ) ; } void Trace( const std::string& str ) ; template void Trace( const std::string& fmt, const P1& p1 ) { LogBase::Inst()->Log( log::Fmt(fmt) % p1, log::debug ) ; } template void Trace( const std::string& fmt, const P1& p1, const P2& p2 ) { LogBase::Inst()->Log( log::Fmt(fmt) % p1 % p2, log::debug ) ; } template void Trace( const std::string& fmt, const P1& p1, const P2& p2, const P3& p3 ) { LogBase::Inst()->Log( log::Fmt(fmt) % p1 % p2 % p3, log::debug ) ; } } // end of namespace Grive-grive-93d696a/libgrive/src/xml/000077500000000000000000000000001177605442600174555ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/src/xml/Error.hh000066400000000000000000000015741177605442600210760ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "util/Exception.hh" namespace gr { namespace xml { struct Error : virtual Exception {} ; } } // end of namespace Grive-grive-93d696a/libgrive/src/xml/Node.cc000066400000000000000000000207371177605442600206620ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Node.hh" #include "Error.hh" #include "NodeSet.hh" #include #include #include #include // debugging #include namespace gr { namespace xml { class Node::Impl { private : typedef std::vector ImplVec ; public : typedef ImplVec::iterator iterator ; typedef ImplVec::const_iterator const_iterator ; public : Impl() : m_ref(1), m_type( element ) { } Impl( const std::string& str, Type type, const std::string& value = "" ) : m_ref(1), m_type( type ), m_name( str ), m_value( value ) { } ~Impl() { std::for_each( m_children.begin(), m_children.end(), std::mem_fun( &Impl::Release ) ) ; } Impl* AddRef() { ++m_ref ; return this ; } void Release() { if ( --m_ref == 0 ) delete this ; } std::size_t RefCount() const { assert( m_ref > 0 ) ; return m_ref ; } void Add( Impl *child ) { assert( child != 0 ) ; assert( child->m_type >= element && child->m_type <= text ) ; ImplVec *map[] = { &m_element, &m_attr, 0 } ; if ( map[child->m_type] != 0 ) { ImplVec& vec = *map[child->m_type] ; std::pair p = std::equal_range( vec.begin(), vec.end(), child, Comp() ) ; // cannot allow duplicate attribute nodes if ( child->m_type == attr && p.first != p.second ) BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "duplicate attribute " + child->m_name ) ) ; vec.insert( p.second, child ) ; } m_children.push_back( child ) ; } Range Find( const std::string& name ) { assert( !name.empty() ) ; return name[0] == '@' ? Find( m_attr, name.substr(1) ) : Find( m_element, name ) ; } Impl* FindAttr( const std::string& name ) { std::pair r = Find( m_attr, name ) ; return r.first != r.second ? *r.first : 0 ; } iterator Begin() { return m_children.begin() ; } iterator End() { return m_children.end() ; } const_iterator Begin() const { return m_children.begin() ; } const_iterator End() const { return m_children.end() ; } std::size_t Size() const { return m_children.size() ; } Range Attr() { return std::make_pair( m_attr.begin(), m_attr.end() ) ; } const std::string& Name() const { return m_name ; } std::string Value() const { assert( m_type != element || m_value.empty() ) ; std::string value = m_value ; for ( const_iterator i = Begin() ; i != End() ; ++i ) value += (*i)->Value() ; return value ; } void Value( const std::string& val ) { m_value = val ; } Type GetType() const { return m_type ; } struct Comp { bool operator()( Impl *p1, Impl *p2 ) const { return p1->Name() < p2->Name() ; } } ; private : Range Find( ImplVec& map, const std::string& name ) { Impl tmp( name , element ) ; return std::equal_range( map.begin(), map.end(), &tmp, Comp() ) ; } private : std::size_t m_ref ; Type m_type ; std::string m_name ; std::string m_value ; ImplVec m_element, m_attr ; ImplVec m_children ; } ; Node::iterator::iterator( ) { } Node::iterator::iterator( ImplVec::iterator i ) { // for some reason, gcc 4.4.4 doesn't allow me to initialize the base class // in the initializer. I have no choice but to initialize here. base_reference() = i ; } Node::iterator::reference Node::iterator::dereference() const { Impl *p = *base_reference() ; assert( p != 0 ) ; return Node( p->AddRef() ) ; } Node::Node() : m_ptr( new Impl ) { } Node::Node( const Node& node ) : m_ptr( node.m_ptr->AddRef() ) { } Node::Node( Impl *impl ) : m_ptr( impl ) { } Node Node::Element( const std::string& name ) { return Node( new Impl( name, element ) ) ; } Node Node::Text( const std::string& name ) { return Node( new Impl( name, text ) ) ; } Node::~Node() { assert( m_ptr != 0 ) ; m_ptr->Release() ; } Node& Node::operator=( const Node& node ) { Node tmp( node ) ; Swap( tmp ) ; return *this ; } void Node::Swap( Node& node ) { std::swap( node.m_ptr, m_ptr ) ; } bool Node::IsCompatible( Type parent, Type child ) { static const bool map[][3] = { // element, attr, text { true, true, true }, // element { false, false, true }, // attribute { false, false, false } // text } ; assert( parent >= element && parent <= text ) ; assert( child >= element && child <= text ) ; return map[parent][child] ; } Node Node::AddElement( const std::string& name ) { assert( m_ptr != 0 ) ; assert( IsCompatible( GetType(), element) ) ; Impl *child = new Impl( name, element ) ; m_ptr->Add( child->AddRef() ) ; return Node( child ) ; } Node Node::AddText( const std::string& str ) { assert( m_ptr != 0 ) ; assert( IsCompatible( GetType(), text ) ) ; Impl *child = new Impl( "#text", text, str ) ; m_ptr->Add( child->AddRef() ) ; return Node( child ) ; } void Node::AddAttribute( const std::string& name, const std::string& val ) { assert( m_ptr != 0 ) ; assert( GetType() == element ) ; m_ptr->Add( new Impl( name, attr, val ) ) ; } void Node::AddNode( const Node& node ) { assert( m_ptr != 0 ) ; assert( node.m_ptr != 0 ) ; assert( IsCompatible( GetType(), node.GetType() ) ) ; m_ptr->Add( node.m_ptr->AddRef() ) ; } void Node::AddNode( iterator first, iterator last ) { for ( iterator i = first ; i != last ; ++i ) AddNode( *i ) ; } NodeSet Node::operator[]( const std::string& name ) const { assert( m_ptr != 0 ) ; assert( !name.empty() ) ; Range is = m_ptr->Find( name ) ; return NodeSet( iterator(is.first), iterator(is.second) ) ; } std::size_t Node::RefCount() const { assert( m_ptr != 0 ) ; return m_ptr->RefCount() ; } Node::Type Node::GetType() const { assert( m_ptr != 0 ) ; return m_ptr->GetType() ; } const std::string& Node::Name() const { assert( m_ptr != 0 ) ; return m_ptr->Name() ; } std::string Node::Value() const { assert( m_ptr != 0 ) ; return m_ptr->Value() ; } Node::operator std::string() const { return Value() ; } bool Node::operator==( const std::string& value ) const { return Value() == value ; } std::ostream& operator<<( std::ostream& os, const Node& node ) { if ( node.GetType() == Node::element ) { os << '<' << node.Name() ; // print attributes NodeSet attrs = node.Attr() ; if ( !attrs.empty() ) os << ' ' << attrs ; os << '>' ; // recursively print children for ( Node::iterator i = node.begin() ; i != node.end() ; ++i ) { if ( (*i).GetType() != Node::attr ) os << *i ; } os << "' ; } else if ( node.GetType() == Node::attr ) { os << node.Name() << "=\"" ; Node::PrintString( os, node.Value() ) ; os << "\"" ; } else { Node::PrintString( os, node.Value() ) ; } return os ; } std::ostream& Node::PrintString( std::ostream& os, const std::string& s ) { for ( std::string::const_iterator i = s.begin() ; i != s.end() ; ++i ) Node::PrintChar( os, *i ) ; return os ; } std::ostream& Node::PrintChar( std::ostream& os, char c ) { switch ( c ) { case '\"': os << """ ; break ; case '\'': os << "'" ; break ; case '&': os << "&" ; break ; case '<': os << "<" ; break ; case '>': os << ">" ; break ; default : os << c ; break ; } return os ; } Node::iterator Node::begin() const { assert( m_ptr != 0 ) ; return iterator( m_ptr->Begin() ) ; } Node::iterator Node::end() const { assert( m_ptr != 0 ) ; return iterator( m_ptr->End() ) ; } std::size_t Node::size() const { assert( m_ptr != 0 ) ; return m_ptr->Size() ; } NodeSet Node::Children() const { assert( m_ptr != 0 ) ; return NodeSet( begin(), end() ) ; } NodeSet Node::Attr() const { assert( m_ptr != 0 ) ; Range is = m_ptr->Attr() ; return NodeSet( iterator(is.first), iterator(is.second) ) ; } std::string Node::Attr( const std::string& attr ) const { assert( m_ptr != 0 ) ; Impl *imp = m_ptr->FindAttr( attr ) ; return imp != 0 ? imp->Value() : "" ; } } } // end namespace Grive-grive-93d696a/libgrive/src/xml/Node.hh000066400000000000000000000054421177605442600206700ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include #include #include namespace gr { namespace xml { class NodeSet ; class Node { private : class Impl ; typedef std::vector ImplVec ; public : class iterator ; public : Node() ; Node( const Node& node ) ; ~Node() ; static Node Element( const std::string& name ) ; static Node Text( const std::string& name ) ; Node& operator=( const Node& node ) ; void Swap( Node& node ) ; Node AddElement( const std::string& name ) ; Node AddText( const std::string& text ) ; void AddNode( const Node& node ) ; void AddNode( iterator first, iterator last ) ; void AddAttribute( const std::string& name, const std::string& val ) ; NodeSet operator[]( const std::string& name ) const ; operator std::string() const ; bool operator==( const std::string& value ) const ; const std::string& Name() const ; std::string Value() const ; // read-only access to the reference counter. for checking. std::size_t RefCount() const ; enum Type { element, attr, text } ; Type GetType() const ; static bool IsCompatible( Type parent, Type child ) ; static std::ostream& PrintChar( std::ostream& os, char c ) ; static std::ostream& PrintString( std::ostream& os, const std::string& s ) ; iterator begin() const ; iterator end() const ; std::size_t size() const ; NodeSet Children() const ; NodeSet Attr() const ; std::string Attr( const std::string& attr ) const ; bool HasAttr( const std::string& attr ) const ; private : explicit Node( Impl *impl ) ; typedef std::pair Range ; private : Impl *m_ptr ; } ; class Node::iterator : public boost::iterator_adaptor< Node::iterator, Node::ImplVec::iterator, Node, boost::random_access_traversal_tag, Node > { public : iterator( ) ; explicit iterator( ImplVec::iterator i ) ; private : friend class boost::iterator_core_access; reference dereference() const ; } ; std::ostream& operator<<( std::ostream& os, const Node& node ) ; } } // end of namespace Grive-grive-93d696a/libgrive/src/xml/NodeSet.cc000066400000000000000000000065751177605442600213420ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "NodeSet.hh" #include "Error.hh" #include #include namespace gr { namespace xml { NodeSet::NodeSet() : m_first( m_tmp.begin() ), m_last( m_tmp.end() ) { } NodeSet::NodeSet( iterator first, iterator last ) : m_first( first ), m_last( last ) { } NodeSet::NodeSet( const NodeSet& n ) : m_tmp( n.m_tmp ), m_first( m_tmp.begin() + (n.m_first - n.m_tmp.begin()) ), m_last( m_tmp.begin() + (n.m_last - n.m_tmp.begin()) ) { } NodeSet& NodeSet::operator=( const NodeSet& ns ) { NodeSet tmp( ns ) ; Swap( tmp ) ; return *this ; } void NodeSet::Swap( NodeSet& ns ) { m_tmp.Swap( ns.m_tmp ) ; std::swap( m_first, ns.m_first ) ; std::swap( m_last, ns.m_last ) ; } NodeSet::iterator NodeSet::begin() const { return m_first ; } NodeSet::iterator NodeSet::end() const { return m_last ; } /*! This function search the members in the node set. If any members in the node set has a children named \a name , with value equal to \a value , it will be returned. \param name name to be found. prefix with '@' for attributes \param value value to be matched. \return the node set contained all children nodes that matches \a name and \a value */ NodeSet NodeSet::Find( const std::string& name, const std::string& value ) const { NodeSet result ; for ( iterator i = m_first ; i != m_last ; ++i ) { NodeSet cand = (*i)[name] ; for ( iterator j = cand.m_first ; j != cand.m_last ; ++j ) { if ( j->Value() == value ) { result.Add( *i ) ; break ; } } } return result ; } void NodeSet::Add( const Node& n ) { // the tmp node is not used, that means the first,last iterators points to elsewhere if ( m_tmp.size() == 0 ) { m_tmp.AddNode( m_first, m_last ) ; } m_tmp.AddNode( n ) ; // the iterators may be invalidated after adding the node m_first = m_tmp.begin() ; m_last = m_tmp.end() ; } NodeSet NodeSet::operator[]( const std::string& name ) const { for ( iterator i = m_first ; i != m_last ; ++i ) { NodeSet r = (*i)[name] ; if ( !r.empty() ) return r ; } return NodeSet() ; } Node NodeSet::front() const { if ( empty() ) throw Error() << expt::ErrMsg( "empty node set" ) ; return *m_first ; } NodeSet::operator std::string() const { return empty() ? "" : front().Value() ; } bool NodeSet::operator==( const std::string& value ) const { return operator std::string() == value ; } bool NodeSet::empty() const { return m_first == m_last ; } std::size_t NodeSet::size() const { return m_last - m_first ; } std::ostream& operator<<( std::ostream& os, const NodeSet& node ) { std::copy( node.begin(), node.end(), std::ostream_iterator(os, " ") ) ; return os ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/xml/NodeSet.hh000066400000000000000000000032301177605442600213350ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Node.hh" #include #include #include namespace gr { namespace xml { class NodeSet { public : typedef Node::iterator iterator ; public : NodeSet() ; NodeSet( const NodeSet& n ) ; NodeSet( iterator first, iterator last ) ; NodeSet& operator=( const NodeSet& ns ) ; void Swap( NodeSet& ns ) ; void Add( const Node& n ) ; iterator begin() const ; iterator end() const ; bool empty() const ; std::size_t size() const ; Node front() const ; NodeSet Find( const std::string& name, const std::string& value ) const ; // forwarding common Node operations to Node operator std::string() const ; NodeSet operator[]( const std::string& name ) const ; bool operator==( const std::string& value ) const ; private : Node m_tmp ; iterator m_first ; iterator m_last ; } ; std::ostream& operator<<( std::ostream& os, const NodeSet& node ) ; } } // end of namespace Grive-grive-93d696a/libgrive/src/xml/String.cc000066400000000000000000000024331177605442600212340ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "String.hh" namespace gr { namespace xml { std::string Escape( const std::string& str ) { std::string result ; for ( std::string::const_iterator i = str.begin() ; i != str.end() ; ++i ) { switch ( *i ) { case '\"': result.append( """ ) ; break ; case '\'': result.append( "'" ) ; break ; case '<': result.append( "<" ) ; break ; case '>': result.append( ">" ) ; break ; case '&': result.append( "&" ) ; break ; default: result.push_back( *i ) ; break ; } } return result ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/xml/String.hh000066400000000000000000000015711177605442600212500ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include namespace gr { namespace xml { std::string Escape( const std::string& str ) ; }} // end of namespace Grive-grive-93d696a/libgrive/src/xml/TreeBuilder.cc000066400000000000000000000064031177605442600221750ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "TreeBuilder.hh" #include "Error.hh" #include "Node.hh" #include #include #include #include namespace gr { namespace xml { struct TreeBuilder::Impl { std::vector stack ; ::XML_Parser psr ; } ; TreeBuilder::TreeBuilder() : m_impl( new Impl ) { m_impl->stack.push_back( Node() ) ; m_impl->psr = ::XML_ParserCreate( 0 ) ; ::XML_SetElementHandler( m_impl->psr, &TreeBuilder::StartElement, &TreeBuilder::EndElement ) ; ::XML_SetCharacterDataHandler( m_impl->psr, &TreeBuilder::OnCharData ) ; ::XML_SetUserData( m_impl->psr , this ) ; } TreeBuilder::~TreeBuilder() { } Node TreeBuilder::ParseFile( const std::string& file ) { TreeBuilder tb ; ::XML_Parser p = tb.m_impl->psr ; std::ifstream f( file.c_str() ) ; const std::size_t block_size = 10 ; std::size_t count = 0 ; while ( (count = f.rdbuf()->sgetn( (char*)::XML_GetBuffer( p, block_size ), block_size ) ) > 0 ) XML_ParseBuffer( p, count, false ) ; XML_ParseBuffer( p, 0, true ) ; return tb.Result() ; } void TreeBuilder::ParseData( const char *data, std::size_t count, bool last ) { if ( ::XML_Parse( m_impl->psr, data, count, last ) == 0 ) throw Error() << expt::ErrMsg( "XML parse error" ) ; } Node TreeBuilder::Parse( const std::string& xml ) { TreeBuilder tb ; tb.ParseData( xml.c_str(), xml.size(), true ) ; return tb.Result() ; } Node TreeBuilder::Result() const { // the node on the stack should be the dummy node with only one child assert( m_impl->stack.size() == 1 ) ; if ( m_impl->stack.front().size() != 1 ) throw Error() << expt::ErrMsg( "invalid node" ) ; return *m_impl->stack.front().begin() ; } void TreeBuilder::StartElement( void *pvthis, const char *name, const char **attr ) { assert( pvthis != 0 ) ; assert( name != 0 ) ; assert( attr != 0 ) ; TreeBuilder *pthis = reinterpret_cast(pvthis) ; Node n = pthis->m_impl->stack.back().AddElement( name ) ; for ( std::size_t i = 0 ; attr[i] != 0 ; i += 2 ) { assert( attr[i+1] != 0 ) ; n.AddAttribute( attr[i], attr[i+1] ) ; } pthis->m_impl->stack.push_back( n ) ; } void TreeBuilder::EndElement( void* pvthis, const char* name ) { TreeBuilder *pthis = reinterpret_cast(pvthis) ; assert( pthis->m_impl->stack.back().Name() == name ) ; pthis->m_impl->stack.pop_back() ; } void TreeBuilder::OnCharData( void *pvthis, const char *s, int len ) { TreeBuilder *pthis = reinterpret_cast(pvthis) ; pthis->m_impl->stack.back().AddText( std::string( s, len ) ) ; } } } // end of namespace Grive-grive-93d696a/libgrive/src/xml/TreeBuilder.hh000066400000000000000000000026431177605442600222110ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace gr { namespace xml { class Node ; class TreeBuilder { public : TreeBuilder() ; ~TreeBuilder() ; void ParseData( const char *data, std::size_t count, bool last = false ) ; Node Result( ) const ; // one shot helpers static Node ParseFile( const std::string& file ) ; static Node Parse( const std::string& xml ) ; private : static void StartElement( void* pvthis, const char* name, const char** attr ) ; static void EndElement( void* pvthis, const char* name ) ; static void OnCharData( void *pvthis, const char *s, int len ) ; private : struct Impl ; std::auto_ptr m_impl ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/test/000077500000000000000000000000001177605442600170455ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/test/Assert.hh000066400000000000000000000054311177605442600206320ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include namespace grut { template void AssertEquals( const T1& expected, const T2& actual, CPPUNIT_NS::SourceLine sourceLine, const std::string& message ) { if ( expected != actual ) { CPPUNIT_NS::Asserter::failNotEqual( CPPUNIT_NS::assertion_traits::toString(expected), CPPUNIT_NS::assertion_traits::toString(actual), sourceLine, message ); } } template void AssertEquals( FwdIt1 actualFirst, FwdIt1 actualLast, FwdIt2 expectFirst, CPPUNIT_NS::SourceLine sourceLine, const std::string& message ) { if ( !std::equal( actualFirst, actualLast, expectFirst ) ) { std::ostringstream exp, act ; while ( actualFirst != actualLast ) { act << *actualFirst++ << " " ; exp << *expectFirst++ << " " ; } CPPUNIT_NS::Asserter::failNotEqual( exp.str(), act.str(), sourceLine, message ); } } inline void AssertEquals( const std::wstring& expected, const std::wstring& actual, CPPUNIT_NS::SourceLine sourceLine, const std::string& message ) { AssertEquals( std::string(expected.begin(), expected.end() ), std::string(actual.begin(), actual.end() ), sourceLine, message ) ; } } // end of namespace #define GRUT_ASSERT_RANGE_EQUAL(actualFirst, actualLast, expectFirst) \ ( grut::AssertEquals( (actualFirst), \ (actualLast), \ (expectFirst), \ CPPUNIT_SOURCELINE(), \ "["#actualFirst","#actualLast") == "#expectFirst) ) #define GRUT_ASSERT_EQUAL(expected, actual) \ ( grut::AssertEquals( (expected), \ (actual), \ CPPUNIT_SOURCELINE(), \ #actual" == "#expected) ) #define GEUT_ASSERT_NULL(actual) \ ( grut::AssertEquals( ((void*)0), \ (actual), \ CPPUNIT_SOURCELINE(), \ #actual" != 0" ) ) Grive-grive-93d696a/libgrive/test/UnitTest.cc000066400000000000000000000031601177605442600211330ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "util/log/DefaultLog.hh" #include "drive/EntryTest.hh" #include "drive/ResourceTest.hh" #include "drive/ResourceTreeTest.hh" #include "drive/StateTest.hh" #include "util/DateTimeTest.hh" #include "util/FunctionTest.hh" #include "util/SignalHandlerTest.hh" #include "xml/NodeTest.hh" int main( int argc, char **argv ) { using namespace grut ; gr::LogBase::Inst( std::auto_ptr(new gr::log::DefaultLog) ) ; CppUnit::TextUi::TestRunner runner; runner.addTest( EntryTest::suite( ) ) ; runner.addTest( StateTest::suite( ) ) ; runner.addTest( ResourceTest::suite( ) ) ; runner.addTest( ResourceTreeTest::suite( ) ) ; runner.addTest( DateTimeTest::suite( ) ) ; runner.addTest( FunctionTest::suite( ) ) ; runner.addTest( SignalHandlerTest::suite( ) ) ; runner.addTest( NodeTest::suite( ) ) ; runner.run(); return 0 ; } Grive-grive-93d696a/libgrive/test/data/000077500000000000000000000000001177605442600177565ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/test/data/entry.xml000066400000000000000000000654521177605442600216550ustar00rootroot00000000000000https://docs.google.com/feeds/default/private/full2012-05-10T16:38:17.968ZAvailable Documents - me@nestal.netmeme@nestal.net110https://docs.google.com/feeds/id/folder%3A0B5KhdsbryVeGMl83OEV1ZVc3cUE2012-05-09T16:13:22.401Z2012-05-09T16:13:22.401Z2012-05-09T16:13:22.401Zsnesmeme@nestal.netfolder:0B5KhdsbryVeGMl83OEV1ZVc3cUEmeme@nestal.net0https://docs.google.com/feeds/id/folder%3A0B5KhdsbryVeGeXhVNHpZSVotN1E2012-05-09T16:11:30.497Z2012-05-09T16:12:05.218Z2012-05-09T16:12:06.869ZLocal Sharedmeme@nestal.netfolder:0B5KhdsbryVeGeXhVNHpZSVotN1E2012-05-09T16:12:05.218Zmeme@nestal.net2012-05-09T16:12:06.863Z0https://docs.google.com/feeds/id/folder%3A0B5KhdsbryVeGNzZGdDlXODBiMVU2012-05-07T04:36:37.993Z2012-05-07T04:36:45.478Z2012-05-09T16:11:49.340Zbinmeme@nestal.netfolder:0B5KhdsbryVeGNzZGdDlXODBiMVU2012-05-07T04:36:45.478Zmeme@nestal.net2012-05-09T16:11:49.334Z0https://docs.google.com/feeds/id/folder%3A0B6HkZFGcyk1-c1RvMEctZ1VuTU02012-05-01T17:03:56.733Z2012-05-01T17:04:04.534Z2012-05-06T12:46:05.931ZShared Subfoldermatch065match065@gmail.comfolder:0B6HkZFGcyk1-c1RvMEctZ1VuTU0match065match065@gmail.com2012-05-06T10:48:52.313Z0https://docs.google.com/feeds/id/folder%3A0B6HkZFGcyk1-anBEVlBjb2dockk2012-05-01T16:31:06.465Z2012-05-01T16:31:31.731Z2012-05-06T12:46:04.899ZSharedmatch065match065@gmail.comfolder:0B6HkZFGcyk1-anBEVlBjb2dockk2012-05-01T16:31:31.735Zmatch065match065@gmail.com2012-05-06T11:00:24.103Z0https://docs.google.com/feeds/id/folder%3A0B5KhdsbryVeGRlZuNEU0ckJneGc2012-04-24T17:07:48.335Z2012-04-24T17:33:54.733Z2012-05-09T16:12:09.328ZSAMSUNG_S MEMOmeme@nestal.netfolder:0B5KhdsbryVeGRlZuNEU0ckJneGc2012-04-24T17:33:54.733Zmeme@nestal.net2012-05-09T16:12:09.322Z0https://docs.google.com/feeds/id/folder%3A0B5KhdsbryVeGNEZjdUxzZHl3Sjg2012-04-24T16:55:48.499Z2012-04-24T16:55:48.499Z2012-05-09T16:13:02.326ZROMsmeme@nestal.netfolder:0B5KhdsbryVeGNEZjdUxzZHl3Sjgmeme@nestal.net2012-05-09T16:13:02.321Z0https://docs.google.com/feeds/id/folder%3A0B5KhdsbryVeGWVpLRDdoa1JrRWs2012-04-24T16:55:48.499Z2012-04-24T16:55:48.499Z2012-05-09T16:11:54.889Zsegameme@nestal.netfolder:0B5KhdsbryVeGWVpLRDdoa1JrRWsmeme@nestal.net2012-05-09T16:11:54.881Z0https://docs.google.com/feeds/id/folder%3A0B5KhdsbryVeGQUFSVUgxeVJSd2M2012-04-24T16:55:48.499Z2012-04-24T16:55:48.499Z2012-04-24T16:55:48.499Zn64meme@nestal.netfolder:0B5KhdsbryVeGQUFSVUgxeVJSd2Mmeme@nestal.net0https://docs.google.com/feeds/id/folder%3A0B5KhdsbryVeGQVpPR192QVJ2Uzg2012-04-24T16:54:34.158Z2012-04-24T16:55:02.919Z2012-05-09T16:11:42.580ZPrivatememe@nestal.netfolder:0B5KhdsbryVeGQVpPR192QVJ2Uzg2012-04-24T16:55:02.919Zmeme@nestal.net2012-05-09T16:11:42.575Z0Grive-grive-93d696a/libgrive/test/data/test_dir1.state000066400000000000000000000006171177605442600227220ustar00rootroot00000000000000{ "change_stamp": "", "rtree": { "name": ".", "id": "folder:root", "href": "https:\/\/docs.google.com\/feeds\/default\/private\/full\/folder%3Aroot", "md5": "", "kind": "folder", "mtime": { "sec": 0, "nsec": 0 }, "child": [ { "name": "entry.xml", "id": "", "href": "", "md5": "c0742c0a32b2c909b6f176d17a6992d0", "kind": "file", "mtime": { "sec": 1336796872, "nsec": 404985662 }, "child": [ ] } ] } }Grive-grive-93d696a/libgrive/test/data/test_dir1/000077500000000000000000000000001177605442600216545ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/test/data/test_dir1/folder1/000077500000000000000000000000001177605442600232105ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/test/data/test_dir1/folder1/abc.txt000066400000000000000000000000031177605442600244670ustar00rootroot00000000000000abcGrive-grive-93d696a/libgrive/test/drive/000077500000000000000000000000001177605442600201565ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/test/drive/EntryTest.cc000066400000000000000000000032751177605442600224350ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "EntryTest.hh" #include "Assert.hh" #include "drive/Entry.hh" #include "xml/Node.hh" #include "xml/NodeSet.hh" #include "xml/TreeBuilder.hh" #include namespace grut { using namespace gr ; EntryTest::EntryTest( ) { } void EntryTest::TestXml( ) { xml::Node root = xml::TreeBuilder::ParseFile( TEST_DATA "entry.xml" ) ; CPPUNIT_ASSERT( !root["entry"].empty() ) ; Entry subject( root["entry"].front() ) ; GRUT_ASSERT_EQUAL( "snes", subject.Title() ) ; GRUT_ASSERT_EQUAL( "\"WxYPGE8CDyt7ImBk\"", subject.ETag() ) ; GRUT_ASSERT_EQUAL( "https://docs.google.com/feeds/default/private/full/folder%3A0B5KhdsbryVeGMl83OEV1ZVc3cUE", subject.SelfHref() ) ; GRUT_ASSERT_EQUAL( 1U, subject.ParentHrefs().size() ) ; GRUT_ASSERT_EQUAL( "https://docs.google.com/feeds/default/private/full/folder%3A0B5KhdsbryVeGNEZjdUxzZHl3Sjg", subject.ParentHrefs().front() ) ; GRUT_ASSERT_EQUAL( "folder", subject.Kind() ) ; } } // end of namespace grut Grive-grive-93d696a/libgrive/test/drive/EntryTest.hh000066400000000000000000000021271177605442600224420ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace grut { class EntryTest : public CppUnit::TestFixture { public : EntryTest( ) ; // declare suit function CPPUNIT_TEST_SUITE( EntryTest ) ; CPPUNIT_TEST( TestXml ) ; CPPUNIT_TEST_SUITE_END(); private : void TestXml( ) ; } ; } // end of namespace Grive-grive-93d696a/libgrive/test/drive/ResourceTest.cc000066400000000000000000000034111177605442600231130ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ResourceTest.hh" #include "Assert.hh" #include "drive/Resource.hh" #include "drive/Entry.hh" #include "xml/Node.hh" #include namespace grut { using namespace gr ; ResourceTest::ResourceTest( ) { } void ResourceTest::TestRootPath() { Resource root ; CPPUNIT_ASSERT( root.IsRoot() ) ; GRUT_ASSERT_EQUAL( root.Path(), fs::path( "." ) ) ; } void ResourceTest::TestNormal( ) { Resource root( TEST_DATA, "folder" ) ; Resource subject( "entry.xml", "file" ) ; root.AddChild( &subject ) ; GRUT_ASSERT_EQUAL( subject.Path(), fs::path( TEST_DATA ) / "entry.xml" ) ; subject.FromLocal( DateTime() ) ; GRUT_ASSERT_EQUAL( subject.MD5(), "c0742c0a32b2c909b6f176d17a6992d0" ) ; GRUT_ASSERT_EQUAL( subject.StateStr(), "local_new" ) ; xml::Node entry = xml::Node::Element( "entry" ) ; entry.AddElement( "updated" ).AddText( "2012-05-09T16:13:22.401Z" ) ; Entry remote( entry ) ; subject.FromRemote( remote, DateTime() ) ; GRUT_ASSERT_EQUAL( subject.StateStr(), "local_changed" ) ; } } // end of namespace grut Grive-grive-93d696a/libgrive/test/drive/ResourceTest.hh000066400000000000000000000022361177605442600231310ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace grut { class ResourceTest : public CppUnit::TestFixture { public : ResourceTest( ) ; // declare suit function CPPUNIT_TEST_SUITE( ResourceTest ) ; CPPUNIT_TEST( TestNormal ) ; CPPUNIT_TEST( TestRootPath ) ; CPPUNIT_TEST_SUITE_END(); private : void TestNormal( ) ; void TestRootPath() ; } ; } // end of namespace Grive-grive-93d696a/libgrive/test/drive/ResourceTreeTest.cc000066400000000000000000000020301177605442600237270ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ResourceTreeTest.hh" #include "Assert.hh" #include "drive/ResourceTree.hh" #include "drive/Resource.hh" #include namespace grut { using namespace gr ; ResourceTreeTest::ResourceTreeTest( ) { } void ResourceTreeTest::TestSerialize( ) { } } // end of namespace grut Grive-grive-93d696a/libgrive/test/drive/ResourceTreeTest.hh000066400000000000000000000021701177605442600237460ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace grut { class ResourceTreeTest : public CppUnit::TestFixture { public : ResourceTreeTest( ) ; // declare suit function CPPUNIT_TEST_SUITE( ResourceTreeTest ) ; CPPUNIT_TEST( TestSerialize ) ; CPPUNIT_TEST_SUITE_END(); private : void TestSerialize( ) ; } ; } // end of namespace Grive-grive-93d696a/libgrive/test/drive/StateTest.cc000066400000000000000000000020101177605442600223760ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "StateTest.hh" #include "Assert.hh" #include "drive/State.hh" #include "protocol/Json.hh" #include "util/log/Log.hh" #include namespace grut { using namespace gr ; StateTest::StateTest( ) { } void StateTest::TestSync( ) { } } // end of namespace grut Grive-grive-93d696a/libgrive/test/drive/StateTest.hh000066400000000000000000000021311177605442600224140ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace grut { class StateTest : public CppUnit::TestFixture { public : StateTest( ) ; // declare suit function CPPUNIT_TEST_SUITE( StateTest ) ; CPPUNIT_TEST( TestSync ) ; CPPUNIT_TEST_SUITE_END(); private : void TestSync( ) ; } ; } // end of namespace Grive-grive-93d696a/libgrive/test/http/000077500000000000000000000000001177605442600200245ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/test/http/MockAgent.cc000066400000000000000000000030241177605442600222020ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "MockAgent.hh" namespace gr { namespace http { MockAgent::MockAgent() { } long MockAgent::Put( const std::string& , const std::string& , Receivable *, const Header& ) { return 200 ; } long MockAgent::Get( const std::string& , Receivable *, const Header& ) { return 200 ; } long MockAgent::Post( const std::string& , const std::string& , Receivable *, const Header& ) { return 200 ; } long MockAgent::Custom( const std::string& , const std::string& , Receivable *, const Header& ) { return 200 ; } std::string MockAgent::RedirLocation() const { return "" ; } std::string MockAgent::Escape( const std::string& str ) { return str ; } std::string MockAgent::Unescape( const std::string& str ) { return str ; } } } // end of namespace Grive-grive-93d696a/libgrive/test/http/MockAgent.hh000066400000000000000000000030531177605442600222160ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include "Agent.hh" namespace gr { namespace http { /*! \brief HTTP mock agent This HTTP agent does nothing. It is used for unit test and dry runs. */ class MockAgent : public Agent { public : MockAgent() ; long Put( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) ; long Get( const std::string& url, Receivable *dest, const Header& hdr ) ; long Post( const std::string& url, const std::string& data, Receivable *dest, const Header& hdr ) ; long Custom( const std::string& method, const std::string& url, Receivable *dest, const Header& hdr ) ; std::string RedirLocation() const ; std::string Escape( const std::string& str ) ; std::string Unescape( const std::string& str ) ; } ; } } // end of namespace Grive-grive-93d696a/libgrive/test/util/000077500000000000000000000000001177605442600200225ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/test/util/DateTimeTest.cc000066400000000000000000000042721177605442600226720ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "DateTimeTest.hh" #include "util/DateTime.hh" #include namespace grut { using namespace gr ; DateTimeTest::DateTimeTest( ) { } void DateTimeTest::TestParseIso( ) { DateTime subject( "2009-07-29T20:31:39.804Z" ) ; struct tm tp = subject.Tm() ; CPPUNIT_ASSERT( tp.tm_year == 109 ) ; CPPUNIT_ASSERT( tp.tm_sec == 39 ) ; CPPUNIT_ASSERT_EQUAL( 804000000UL, subject.NanoSec() ) ; } void DateTimeTest::TestParseNoMillisec( ) { DateTime subject( "2009-07-29T20:31:39Z" ) ; CPPUNIT_ASSERT_EQUAL( 0UL, subject.NanoSec() ) ; } void DateTimeTest::TestParseInvalid( ) { DateTime subject( "abcdefg" ) ; CPPUNIT_ASSERT_EQUAL( static_cast(0), subject.Sec() ) ; CPPUNIT_ASSERT_EQUAL( 0UL, subject.NanoSec() ) ; } void DateTimeTest::TestOffByOne( ) { DateTime subject( "2008-12-21T02:48:53.940Z" ) ; struct tm tp = subject.Tm() ; CPPUNIT_ASSERT_EQUAL( 21, tp.tm_mday ) ; } void DateTimeTest::TestCompare( ) { DateTime s1( 1000, 2000 ), s2( 1001, 2000 ), s3( 1000, 2001 ), s4( 1001, 2000 ) ; CPPUNIT_ASSERT( s1 < s3 ) ; CPPUNIT_ASSERT( s1 <= s3 ) ; CPPUNIT_ASSERT( s3 > s1 ) ; CPPUNIT_ASSERT( s3 >= s1 ) ; CPPUNIT_ASSERT( s1 < s2 ) ; CPPUNIT_ASSERT( s1 <= s2 ) ; CPPUNIT_ASSERT( s2 > s1 ) ; CPPUNIT_ASSERT( s2 >= s1 ) ; CPPUNIT_ASSERT( s2 == s4 ) ; CPPUNIT_ASSERT( s2 >= s4 ) ; CPPUNIT_ASSERT( s2 <= s4 ) ; CPPUNIT_ASSERT( s4 == s2 ) ; CPPUNIT_ASSERT( s4 >= s2 ) ; CPPUNIT_ASSERT( s4 <= s2 ) ; } } // end of namespace grut Grive-grive-93d696a/libgrive/test/util/DateTimeTest.hh000066400000000000000000000025421177605442600227020ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace grut { class DateTimeTest : public CppUnit::TestFixture { public : DateTimeTest( ) ; // declare suit function CPPUNIT_TEST_SUITE( DateTimeTest ) ; CPPUNIT_TEST( TestParseIso ) ; CPPUNIT_TEST( TestParseNoMillisec ) ; CPPUNIT_TEST( TestOffByOne ) ; CPPUNIT_TEST( TestParseInvalid ) ; CPPUNIT_TEST( TestCompare ) ; CPPUNIT_TEST_SUITE_END(); private : void TestParseIso( ) ; void TestParseNoMillisec( ) ; void TestOffByOne( ) ; void TestParseInvalid( ) ; void TestCompare( ) ; } ; } // end of namespace Grive-grive-93d696a/libgrive/test/util/FunctionTest.cc000066400000000000000000000021701177605442600227560ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "FunctionTest.hh" #include "util/Function.hh" namespace grut { using namespace gr ; FunctionTest::FunctionTest( ) { } int TestFunction( int v ) { return v ; } void FunctionTest::TestRun( ) { Function f = &TestFunction ; Function f2 ; CPPUNIT_ASSERT_EQUAL( 3, f(3) ) ; CPPUNIT_ASSERT_EQUAL( std::string(), f2() ) ; } } // end of namespace grut Grive-grive-93d696a/libgrive/test/util/FunctionTest.hh000066400000000000000000000021401177605442600227650ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace grut { class FunctionTest : public CppUnit::TestFixture { public : FunctionTest( ) ; // declare suit function CPPUNIT_TEST_SUITE( FunctionTest ) ; CPPUNIT_TEST( TestRun ) ; CPPUNIT_TEST_SUITE_END(); private : void TestRun( ) ; } ; } // end of namespace Grive-grive-93d696a/libgrive/test/util/SignalHandlerTest.cc000066400000000000000000000025161177605442600237100ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "SignalHandlerTest.hh" #include "util/SignalHandler.hh" #include void test_callback( int ) { } namespace grut { using namespace gr ; SignalHandlerTest::SignalHandlerTest( ) { } void SignalHandlerTest::TestMultipleSignals( ) { SignalHandler::GetInstance().RegisterSignal( SIGINT, &test_callback ); CPPUNIT_ASSERT_THROW( SignalHandler::GetInstance().RegisterSignal( SIGINT, &test_callback ), SignalError); SignalHandler::GetInstance().UnregisterSignal( SIGINT ); CPPUNIT_ASSERT_NO_THROW( SignalHandler::GetInstance().RegisterSignal( SIGINT, &test_callback )); } } Grive-grive-93d696a/libgrive/test/util/SignalHandlerTest.hh000066400000000000000000000022071177605442600237170ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace grut { class SignalHandlerTest : public CppUnit::TestFixture { public : SignalHandlerTest( ) ; // declare suit function CPPUNIT_TEST_SUITE( SignalHandlerTest ) ; CPPUNIT_TEST( TestMultipleSignals ) ; CPPUNIT_TEST_SUITE_END(); private : void TestMultipleSignals( ) ; } ; } // end of namespace Grive-grive-93d696a/libgrive/test/xml/000077500000000000000000000000001177605442600176455ustar00rootroot00000000000000Grive-grive-93d696a/libgrive/test/xml/NodeTest.cc000066400000000000000000000044651177605442600217120ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "NodeTest.hh" #include "Assert.hh" #include "xml/Node.hh" #include "xml/NodeSet.hh" #include "xml/TreeBuilder.hh" #include namespace grut { using namespace gr::xml ; NodeTest::NodeTest( ) { } void NodeTest::TestTree( ) { Node node = Node::Element( "root" ) ; GRUT_ASSERT_EQUAL( 1UL, node.RefCount() ) ; GRUT_ASSERT_EQUAL( Node::element, node.GetType() ) ; Node c1 = node.AddElement( "child1" ) ; c1.AddText( "this is a line" ) ; Node c11 = c1.AddElement( "b" ) ; GRUT_ASSERT_EQUAL( 2UL, c1.RefCount() ) ; Node c2 = node.AddElement( "child2" ) ; Node c0 = node.AddElement( "child0" ) ; Node c1_ = node["child1"].front() ; Node c11_ = node["child1"]["b"].front() ; GRUT_ASSERT_EQUAL( 3UL, c1_.RefCount() ) ; GRUT_ASSERT_EQUAL( "child1", c1_.Name() ) ; } void NodeTest::TestParseFile( ) { Node n ; n.AddNode( TreeBuilder::Parse( "abc" ) ) ; GRUT_ASSERT_EQUAL( "entry", n["entry"].front().Name() ) ; GRUT_ASSERT_EQUAL( "link", n["entry"]["link"].front().Name() ) ; GRUT_ASSERT_EQUAL( "q", n["entry"]["link"]["@href"].front().Value() ) ; GRUT_ASSERT_EQUAL( Node::element, n["entry"]["link"]["href"].front().GetType() ) ; GRUT_ASSERT_EQUAL( "abc", n["entry"]["link"]["href"].front().Value() ) ; Node el = n["entry"]["link"].front() ; Node::iterator i = el.begin() ; while ( i != el.end() ) { CPPUNIT_ASSERT_EQUAL( std::string("href"), (*i).Name() ) ; ++i ; } NodeSet r = n["entry"]["link"] ; GRUT_ASSERT_EQUAL( 2U, r.size() ) ; } } // end of namespace grut Grive-grive-93d696a/libgrive/test/xml/NodeTest.hh000066400000000000000000000022211177605442600217100ustar00rootroot00000000000000/* grive: an GPL program to sync a local directory with Google Drive Copyright (C) 2012 Wan Wai Ho This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include namespace grut { class NodeTest : public CppUnit::TestFixture { public : NodeTest( ) ; // declare suit function CPPUNIT_TEST_SUITE( NodeTest ) ; CPPUNIT_TEST( TestTree ) ; CPPUNIT_TEST( TestParseFile ) ; CPPUNIT_TEST_SUITE_END(); private : void TestTree( ) ; void TestParseFile( ) ; } ; } // end of namespace Grive-grive-93d696a/package/000077500000000000000000000000001177605442600156565ustar00rootroot00000000000000Grive-grive-93d696a/package/fedora16/000077500000000000000000000000001177605442600172655ustar00rootroot00000000000000Grive-grive-93d696a/package/fedora16/grive.spec000066400000000000000000000040521177605442600212560ustar00rootroot00000000000000#Correct it to 1 if you want git snapshot version %global git 0 %if !%{git} #Should be corrected to match the Version %global gitcommit da89bf2 %else %global gitcommit b6fb4a6 %global gitfull b6fb4a604e51009ece1d8cfe7b45ed603097b47c %global date 20120531 %endif Name: grive Version: 0.1.1 %if %{git} Release: 1.%{date}git%{gitcommit}%{?dist} %else Release: 1%{?dist} %endif Summary: An open source Linux client for Google Drive License: GPLv2 URL: http://grive.github.com/grive/ %if %{git} Source0: https://github.com/grive/%{name}/tarball/%{gitfull} %else Source0: https://github.com/grive/%{name}/tarball/v%{version} %endif BuildRequires: cmake BuildRequires: libstdc++-devel BuildRequires: libcurl-devel BuildRequires: json-c-devel BuildRequires: expat-devel BuildRequires: openssl-devel BuildRequires: boost-devel BuildRequires: binutils-devel %description The purpose of this project is to provide an independent implementation of Google Drive client. It uses the Google Document List API to talk to the servers in Google. The code is written in standard C++. %package devel Summary: Development files for grive Requires: %{name}%{?_isa} = %{version}-%{release} %description devel Development files for grive %prep %setup -q -n Grive-%{name}-%{gitcommit} %build %cmake . make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %doc COPYING README %{_bindir}/%{name} %{_libdir}/libgrive.so.* %files devel %{_includedir}/%{name}* %{_libdir}/libgrive.so %changelog * Sat Jun 09 2012 Nestal Wan 0.1.1-1 - Updated for new repository location * Thu Jun 07 2012 Vasiliy N. Glazov 0.1.0-1 - Jump to release versioning * Tue May 10 2012 Vasiliy N. Glazov 0.1.0-1.20120528git07553e5.R - Update to 0.1.0 * Tue May 10 2012 Vasiliy N. Glazov 0.0.4-20120510git0c3fdaa.1.R - Initial release