From c1d9090d7ca9966e4e908921b1e5d3367e74f1af Mon Sep 17 00:00:00 2001 From: "Theodore R. Smith" Date: Fri, 9 Aug 2024 08:51:51 -0500 Subject: [PATCH 01/33] Fork notice. --- README | 307 +-------------------------------------------------------- 1 file changed, 2 insertions(+), 305 deletions(-) diff --git a/README b/README index 15e22f7..abeb065 100644 --- a/README +++ b/README @@ -20,310 +20,7 @@ password. Mega website can be found at https://mega.nz. -Megatools official website is at https://megatools.megous.com +# This has been forekd and is actively maintained: +https://github.com/BitBasket/megatools -Tools -===== - - reg Register and verify a new mega account - df Show your cloud storage space usage/quota - ls List all remote files - test Test for existence of remote files or folders - export Create public links for remote files - mkdir Create remote directory - rm Remove remote file or directory - put Upload individual files - get Download individual files - dl Download file from a "public" Mega link - (doesn't require login) - copy Upload or download a directory tree - - -All of these tools do: - -- Local caching of remote session/filesystem information - for faster execution. Cache is encrypted with your password key. -- Support loading login credentials from a configuration file. - - -Usage -===== - -See the man pages for how to use individual tools: - - man megatools - -Man pages are also available online at: - - https://megatools.megous.com/man/megatools.html - - -Installation on Windows -======================= - -Official builds for 32bit and 64bit Windows are avaialbe at: - - https://megatools.megous.com - https://megatools.megous.com/builds/experimental/ - -Megatools is also available on Windows via Chocolatey thanks to ERap320. -See: - - https://chocolatey.org/packages/megatools/ - -You can contact the chockolatey package maintainer here: - - https://github.com/megous/megatools/issues/347 - - -Windows Quirks -============== - -On Windows, if you see weird characters in your megals output, you'll need -to set correct CHARSET environment variable. For example on Czech Windows -this would mean executing this command in cmd before using the tools: - - set CHARSET=CP852 - -This is just a cosmetic issue. Internally, megatools always work with UTF-8 -file names, and even if the tool's terminal output is corrupted, files names -of downloaded/uploaded files will be correct. - - -Installation on macOS -===================== - -Thanks to Carl Moden, megatools is available in Homebrew (http://brew.sh/). - -You can therefore install megatools with: - - brew install megatools - - -Installation on your favorite GNU/Linux distribution -==================================================== - -Megatools may already be pre-packaged in the package repository -of your distribution. It is already available at least in: - -- Arch Linux (AUR) - https://aur.archlinux.org/packages/megatools/ -- Debian - https://packages.debian.org/sid/megatools -- Fedora - https://admin.fedoraproject.org/pkgdb/package/rpms/megatools/ -- Gentoo - https://packages.gentoo.org/packages/net-misc/megatools -- openSUSE - https://software.opensuse.org/package/megatools -- Ubuntu - https://packages.ubuntu.com/cosmic/megatools - -Be sure to check your distribution's package repository first. - - -Installation on FreeBSD -======================= - -Megatools is available in ports thanks to Maxim V. Kostikov: - - https://www.freshports.org/net/megatools/ - - -Using a static build for Linux -============================== - -Experimental static build is available since version 1.11.0. This build provides -a single megatools binary that can be copied to any GNU/Linux distribution and -run from there. It is reported that you can even copy an ARM build to your -Android smartphone and run it from your phone. - -This build is useful if you want to avoid the hassle of bulding megatools on old -distributions like older versions of CentOS or RedHat. - -Static builds are available here: - - https://megatools.megous.com/builds/experimental/ - - -Building megatools from source code -=================================== - -The official source code tarball is available at: - - http://megatools.megous.com/builds/ - -You should check that the code was released by me by verifying PGP signatures -provided alongside the code. - -You will need to install a few dependnencies before you can build megatools from -source code. Package names of these dependencies differ depending on your -GNU/Linux distribution. - -Runtime dependencies are: glib2, libcurl and openssl - -Build time dependencies are: gcc, make, pkg-config (pkgconf) - - -On Debian, Ubuntu: - - apt-get -y install build-essential libglib2.0-dev libssl-dev \ - libcurl4-openssl-dev - -On Fedora and CentOS: - - yum -y install gcc make glib2-devel libcurl-devel openssl-devel - -On OpenSUSE: - - zypper -n install gcc make glib2-devel libcurl-devel openssl-devel - -On Arch Linux: - - pacman -Sy --noconfirm --needed pkgconf gcc make glib2 curl - -On Alpine Linux: - - apk add --update build-base libcurl curl-dev asciidoc openssl-dev glib-dev \ - glib libtool automake autoconf - - -You can build megatools into your HOME directory, so that they'll not pollute -your /usr or /usr/local by using --prefix=$HOME/.local option to configure. - -Example build steps: - - wget https://megatools.megous.com/builds/megatools-1.10.2.tar.gz{,.asc} - gpg --verify megatools-1.10.2.tar.gz.asc - cd megatools-1.10.2 - ./configure --prefix=$HOME/.local - make -j4 - make install - -If you encounter issues, read the error messages carefully. They may contain -hints on how you can solve the issue yourself (missing dependencies, missing -C compiler build flags, etc.). - -Now you can run megatools from ~/.local/bin. - - export PATH="$HOME/.local/bin:$PATH" - megals - - -Building megatools from git repository and contributing code -============================================================ - -Building from git is discouraged for most users, unless you want to contribute -your code to megatools. - -Please don't report build issues against code that you downloaded from git if -you're an end user and don't intend to do development on megatools. This is not -a supported method of building megatools for end users, and it is not expected -to work on all distributions, or at all. If you're an end user, just use the -official tarball. If you're a developer and want help with building megatools -from git, make sure to mention it, otherwise I'll assume you're an end user and -just refer you to this README. - -If you want to develop megatools, you can send patches via e-mail to -megous@megous.com or create pull requests on github. E-mail is the preferred -method. - -In addition to the regular build steps, you'll need to install additional -dependencies. For building from git repository, you'll also need: asciidoc, -docbook-xml, autoconf, libtool, automake. - -Now, get the code using git: - - git clone git://megous.com/megatools - -Documentation is built separately from the code, and must be built first. -Running make -C docs should build the docs, if you have all the dependencies -installed correctly. - -Run ./autogen.sh instead of ./configure - -The rest of the steps is the same as the regular source code build. - -Example build steps: - - git clone git://megous.com/megatools - cd megatools - make -j8 -C docs - ./autogen.sh --prefix=$HOME/.local - make -j4 - make install - - -Third party tools/scripts -========================= - -Megatools are meant as a low-level tools that can be used as a base to create -more complicated tools for working with mega.nz. Other people have created -a third party scripts on top of megatools. If you're one of them and want to -have your project listed here, let me know. - -Some third party tools can be found at: - - https://amourspirit.github.io/mega_scripts/ - - -Author -====== - -Megatools were written by Ondřej Jirman , 2013-2018 - -My PGP key can be found at: https://megous.com/dl/key.txt - (Fingerprint is: 9AB138B20691621CD4CF92026E6426C677CFEFF1) - -Official website is: https://megatools.megous.com - -If you'd like to donate, please use contact information provided on the -official website. - - -Contributors -============ - -- Chris Tarazi -- Tom Maneiro -- bAndie91 -- Alberto Garcia -- David Guillen Fandos -- Erik Nordstrøm -- Johnathan Jenkins -- Kagami Hiiragi -- Matthew Schultz -- Michael Ledin -- Michael Ripley -- Palmer Dabbelt -- RealDolos -- Viktor (Icon) VAD -- cyrozap -- nyuszika7h -- protomouse -- strupo -- wdlkmpx -- dal1a -- Max Base - - -Support and bug reports -======================= - -If you think you've found bug in megatools, send a report including enough -information for recreating the issue to: megous@megous.com - -IMPORTANT: I use personal e-mail server for my e-mail communication. I respond -to most e-mails, so if you are not getting a response within a few days, and -you're a user of a more aggressive e-mail provider (Outlook, iCloud, ...) it may -be because your provider rejected my e-mail as SPAM and did not deliver it at -all (not even to your SPAM folder), despite it being response to your e-mail and -my server using industry's best practices. You can either contact your e-mail -provider so that they fix their issue with rejecting legitimate responses to -your mail, or use different e-mail provider or contact channel to contact me. -(github issues) - - -License -======= - -Megatools are licensed under GPLv2 with OpenSSL exemption, see LICENSE -file for details. - -This product includes software developed by the OpenSSL Project for use -in the OpenSSL Toolkit. (http://www.openssl.org/) From 43a975b49b69e73d5e408bf3f0b5ddacfce33050 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sun, 24 Mar 2019 17:59:16 +0100 Subject: [PATCH 02/33] URL-decode links passed to the dl command #310 --- tools/dl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/dl.c b/tools/dl.c index 321f54a..5d1987f 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -381,7 +381,8 @@ static int dl_main(int ac, char *av[]) gc_free gchar *key = NULL; gc_free gchar *handle = NULL; gc_free gchar *specific = NULL; - gc_free gchar *link = tool_convert_filename(av[i], FALSE); + gc_free gchar *link_utf8 = tool_convert_filename(av[i], FALSE); + gc_free gchar *link = g_uri_unescape_string(link_utf8, NULL); // Codes can move to tools.c (tool convert filename function) link = g_uri_unescape_string(link, NULL); From 0b9da21a7b39df52714d891af0bfcee8c0bc775a Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sat, 13 Apr 2019 21:31:20 +0200 Subject: [PATCH 03/33] Change e-mail/website addresses --- HACKING | 12 ------------ Makefile.am | 4 ++-- README | 2 +- docs/footer.txt | 5 +++-- 4 files changed, 6 insertions(+), 17 deletions(-) delete mode 100644 HACKING diff --git a/HACKING b/HACKING deleted file mode 100644 index 1a5e7f3..0000000 --- a/HACKING +++ /dev/null @@ -1,12 +0,0 @@ -How to contribute to megatools -============================== - -If you want to contribute code to megatools, you can fork -official git repository at: - - https://github.com/megous/megatools - -To contribute bug reports and feature requests, use issue -tracker at github: - - https://github.com/megous/megatools/issues diff --git a/Makefile.am b/Makefile.am index 65b5ddf..c55c5a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -70,9 +70,9 @@ man5_MANS = $(addprefix docs/,$(addsuffix .5, $(MAN5))) EXTRA_DIST += $(man1_MANS) $(man5_MANS) -EXTRA_DIST += LICENSE HACKING contrib/bash-completion/megatools +EXTRA_DIST += LICENSE contrib/bash-completion/megatools -doc_DATA = LICENSE NEWS TODO README INSTALL HACKING +doc_DATA = LICENSE NEWS TODO README INSTALL EXTRA_DIST += \ docs/auth-options.txt \ diff --git a/README b/README index abeb065..8c16f1f 100644 --- a/README +++ b/README @@ -21,6 +21,6 @@ password. Mega website can be found at https://mega.nz. -# This has been forekd and is actively maintained: +# This has been forked and is actively maintained: https://github.com/BitBasket/megatools diff --git a/docs/footer.txt b/docs/footer.txt index a05d21f..7f1f7ca 100644 --- a/docs/footer.txt +++ b/docs/footer.txt @@ -21,12 +21,13 @@ Part of the man:megatools[1] suite of commands. BUGS ---- -Report bugs at link:https://github.com/megous/megatools[] or megous@megous.com. +Report bugs to megatools@megous.com. Your message will end up in a public +archive, so be careful what you say or send. AUTHOR ------ -Megatools was written by Ondrej Jirman , 2013-2018. +Megatools was written by Ondrej Jirman , 2013-2019. Official website is link:http://megatools.megous.com[]. From 36f580d3383051213c3132bae369cb588371c299 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Wed, 8 May 2019 14:03:17 +0200 Subject: [PATCH 04/33] Mark some functions as static --- tools/dl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/dl.c b/tools/dl.c index 5d1987f..b11fbaa 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -214,7 +214,7 @@ static gint compare_node(struct mega_node *a, struct mega_node *b) return 0; } -GSList* prune_children(GSList* nodes) +static GSList* prune_children(GSList* nodes) { GSList* pruned = NULL, *it, *it2; @@ -245,7 +245,7 @@ prune_node:; return g_slist_reverse(pruned); } -GSList* pick_nodes(void) +static GSList* pick_nodes(void) { GSList *nodes = mega_session_ls(s, "/", TRUE), *it, *chosen_nodes; int position = 2; From c8f10bbcab34c93b835544d5d4d72a4d62fcf22a Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sat, 8 Jun 2019 14:21:37 +0200 Subject: [PATCH 05/33] We need to follow symlinks on local paths in megatools dl Reported by Alex --- tools/dl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/dl.c b/tools/dl.c index b11fbaa..1e4efd2 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -79,7 +79,7 @@ static gboolean dl_sync_file(struct mega_node *node, GFile *file) return FALSE; } } else { - if (g_file_query_file_type(parent, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) != G_FILE_TYPE_DIRECTORY) { + if (g_file_query_file_type(parent, 0, NULL) != G_FILE_TYPE_DIRECTORY) { g_printerr("ERROR: Can't create local directory %s: a file exists there!\n", parent_path); return FALSE; } @@ -437,8 +437,7 @@ static int dl_main(int ac, char *av[]) struct mega_node *root_node = l->data; gc_object_unref GFile *local_dir = g_file_new_for_path(opt_path); - if (g_file_query_file_type(local_dir, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL) == G_FILE_TYPE_DIRECTORY) { + if (g_file_query_file_type(local_dir, 0, NULL) == G_FILE_TYPE_DIRECTORY) { if (opt_choose_files) { if (!dl_sync_dir_choose(local_dir)) status = 1; From bf755ffbf0c99fd513697c12779a87df1a355142 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sun, 21 Jul 2019 14:32:58 +0200 Subject: [PATCH 06/33] Update PGP fingerprint --- README | 1 - 1 file changed, 1 deletion(-) diff --git a/README b/README index 8c16f1f..2979c99 100644 --- a/README +++ b/README @@ -23,4 +23,3 @@ Mega website can be found at https://mega.nz. # This has been forked and is actively maintained: https://github.com/BitBasket/megatools - From 6756f189b5d8c7fd32ab724dcff6fb3bd2d03bb3 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Tue, 6 Aug 2019 09:13:12 +0200 Subject: [PATCH 07/33] Drop github issue template --- .github/ISSUE_TEMPLATE/bug_report.md | 31 ---------------------------- 1 file changed, 31 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 0e786ff..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior. Usually an actual failing command line command. - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Environment:** - - OS and version: [e.g. CentOS 3] - - **Megatools version**: - -**Debug output** (if appropriate) - - Provide debug output by running the tool with --debug http,api - - Sanitize it (remove session IDs, whatever other private info you want removed, etc.), or send it directly to megous@megous.com to avoid github.com. Most of the output is safe to be posted, except for session ids. Anyone can delete all your files, or cause some other mess just by knowing the session id. - - Most of the debug output is already encrypted and useless on its own, without knowing the password. Alternatively, use an empty test account for debugging. - -**Self help** - - If it is a build issue, review the README file carefully, before submitting a bug report. - - Did you donwload code from git (this is an unsupported build method, unless you want to contribute your code), or did you use a source code release tarball from https://megatools.megous.com? - - If error seems transient (error 509, ERATELIMIT, ...), wait a bit and retry the command, before reporting issues. - - Run megatools with --debug http,api and check if anything seems out of place (for CURL errors, certificate errors, API errors (EXXXXX), etc.) - - Look through [recently closed issues](https://github.com/megous/megatools/issues?q=is%3Aissue+is%3Aclosed) - - For compilation errors, if you're running an esoteric/old platform/OS, try to fix the error yourself and send the patch. From 7476f7c6e1f5807ebae424047bb5911b7c65c637 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Tue, 6 Aug 2019 09:13:46 +0200 Subject: [PATCH 08/33] Move to meson buildystem --- INSTALL | 370 -------------------------------------------- Makefile.am | 89 ----------- autogen.sh | 25 --- configure.ac | 71 --------- docs/Makefile | 31 ---- install-symlinks.sh | 10 ++ meson.build | 118 ++++++++++++++ meson_options.txt | 11 ++ 8 files changed, 139 insertions(+), 586 deletions(-) delete mode 100644 INSTALL delete mode 100644 Makefile.am delete mode 100755 autogen.sh delete mode 100644 configure.ac delete mode 100644 docs/Makefile create mode 100644 install-symlinks.sh create mode 100644 meson.build create mode 100644 meson_options.txt diff --git a/INSTALL b/INSTALL deleted file mode 100644 index d60e29a..0000000 --- a/INSTALL +++ /dev/null @@ -1,370 +0,0 @@ -Installation Instructions -************************* - -Copyright (C) 1994-1996, 1999-2002, 2004-2012 Free Software Foundation, -Inc. - - Copying and distribution of this file, with or without modification, -are permitted in any medium without royalty provided the copyright -notice and this notice are preserved. This file is offered as-is, -without warranty of any kind. - -Basic Installation -================== - - Briefly, the shell commands './configure; make; make install' should -configure, build, and install this package. The following -more-detailed instructions are generic; see the 'README' file for -instructions specific to this package. Some packages provide this -'INSTALL' file but do not implement all of the features documented -below. The lack of an optional feature in a given package is not -necessarily a bug. More recommendations for GNU packages can be found -in *note Makefile Conventions: (standards)Makefile Conventions. - - The 'configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a 'Makefile' in each directory of the package. -It may also create one or more '.h' files containing system-dependent -definitions. Finally, it creates a shell script 'config.status' that -you can run in the future to recreate the current configuration, and a -file 'config.log' containing compiler output (useful mainly for -debugging 'configure'). - - It can also use an optional file (typically called 'config.cache' -and enabled with '--cache-file=config.cache' or simply '-C') that saves -the results of its tests to speed up reconfiguring. Caching is -disabled by default to prevent problems with accidental use of stale -cache files. - - If you need to do unusual things to compile the package, please try -to figure out how 'configure' could check whether to do them, and mail -diffs or instructions to the address given in the 'README' so they can -be considered for the next release. If you are using the cache, and at -some point 'config.cache' contains results you don't want to keep, you -may remove or edit it. - - The file 'configure.ac' (or 'configure.in') is used to create -'configure' by a program called 'autoconf'. You need 'configure.ac' if -you want to change it or regenerate 'configure' using a newer version -of 'autoconf'. - - The simplest way to compile this package is: - - 1. 'cd' to the directory containing the package's source code and type - './configure' to configure the package for your system. - - Running 'configure' might take a while. While running, it prints - some messages telling which features it is checking for. - - 2. Type 'make' to compile the package. - - 3. Optionally, type 'make check' to run any self-tests that come with - the package, generally using the just-built uninstalled binaries. - - 4. Type 'make install' to install the programs and any data files and - documentation. When installing into a prefix owned by root, it is - recommended that the package be configured and built as a regular - user, and only the 'make install' phase executed with root - privileges. - - 5. Optionally, type 'make installcheck' to repeat any self-tests, but - this time using the binaries in their final installed location. - This target does not install anything. Running this target as a - regular user, particularly if the prior 'make install' required - root privileges, verifies that the installation completed - correctly. - - 6. You can remove the program binaries and object files from the - source code directory by typing 'make clean'. To also remove the - files that 'configure' created (so you can compile the package for - a different kind of computer), type 'make distclean'. There is - also a 'make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - - 7. Often, you can also type 'make uninstall' to remove the installed - files again. In practice, not all packages have tested that - uninstallation works correctly, even though it is required by the - GNU Coding Standards. - - 8. Some packages, particularly those that use Automake, provide `make - distcheck', which can by used by developers to test that all other - targets like 'make install' and 'make uninstall' work correctly. - This target is generally not run by end users. - -Compilers and Options -===================== - - Some systems require unusual options for compilation or linking that -the 'configure' script does not know about. Run './configure --help' -for details on some of the pertinent environment variables. - - You can give 'configure' initial values for configuration parameters -by setting variables in the command line or in the environment. Here -is an example: - - ./configure CC=c99 CFLAGS=-g LIBS=-lposix - - *Note Defining Variables::, for more details. - -Compiling For Multiple Architectures -==================================== - - You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you can use GNU 'make'. 'cd' to the -directory where you want the object files and executables to go and run -the 'configure' script. 'configure' automatically checks for the -source code in the directory that 'configure' is in and in '..'. This -is known as a "VPATH" build. - - With a non-GNU 'make', it is safer to compile the package for one -architecture at a time in the source code directory. After you have -installed the package for one architecture, use 'make distclean' before -reconfiguring for another architecture. - - On MacOS X 10.5 and later systems, you can create libraries and -executables that work on multiple system types--known as "fat" or -"universal" binaries--by specifying multiple '-arch' options to the -compiler but only a single '-arch' option to the preprocessor. Like -this: - - ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ - CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ - CPP="gcc -E" CXXCPP="g++ -E" - - This is not guaranteed to produce working output in all cases, you -may have to build one architecture at a time and combine the results -using the 'lipo' tool if you have problems. - -Installation Names -================== - - By default, 'make install' installs the package's commands under -'/usr/local/bin', include files under '/usr/local/include', etc. You -can specify an installation prefix other than '/usr/local' by giving -'configure' the option '--prefix=PREFIX', where PREFIX must be an -absolute file name. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -pass the option '--exec-prefix=PREFIX' to 'configure', the package uses -PREFIX as the prefix for installing programs and libraries. -Documentation and other data files still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like '--bindir=DIR' to specify different values for particular -kinds of files. Run 'configure --help' for a list of the directories -you can set and what kinds of files go in them. In general, the -default for these options is expressed in terms of '${prefix}', so that -specifying just '--prefix' will affect all of the other directory -specifications that were not explicitly provided. - - The most portable way to affect installation locations is to pass the -correct locations to 'configure'; however, many packages provide one or -both of the following shortcuts of passing variable assignments to the -'make install' command line to change installation locations without -having to reconfigure or recompile. - - The first method involves providing an override variable for each -affected directory. For example, `make install -prefix=/alternate/directory' will choose an alternate location for all -directory configuration variables that were expressed in terms of -'${prefix}'. Any directories that were specified during 'configure', -but not in terms of '${prefix}', must each be overridden at install -time for the entire installation to be relocated. The approach of -makefile variable overrides for each directory variable is required by -the GNU Coding Standards, and ideally causes no recompilation. -However, some platforms have known limitations with the semantics of -shared libraries that end up requiring recompilation when using this -method, particularly noticeable in packages that use GNU Libtool. - - The second method involves providing the 'DESTDIR' variable. For -example, 'make install DESTDIR=/alternate/directory' will prepend -'/alternate/directory' before all installation names. The approach of -'DESTDIR' overrides is not required by the GNU Coding Standards, and -does not work on platforms that have drive letters. On the other hand, -it does better at avoiding recompilation issues, and works well even -when some directory options were not specified in terms of '${prefix}' -at 'configure' time. - -Optional Features -================= - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving 'configure' the -option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. - - Some packages pay attention to '--enable-FEATURE' options to -'configure', where FEATURE indicates an optional part of the package. -They may also pay attention to '--with-PACKAGE' options, where PACKAGE -is something like 'gnu-as' or 'x' (for the X Window System). The -'README' should mention any '--enable-' and '--with-' options that the -package recognizes. - - For packages that use the X Window System, 'configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the 'configure' options '--x-includes=DIR' and -'--x-libraries=DIR' to specify their locations. - - Some packages offer the ability to configure how verbose the -execution of 'make' will be. For these packages, running `./configure ---enable-silent-rules' sets the default to minimal output, which can be -overridden with 'make V=1'; while running `./configure ---disable-silent-rules' sets the default to verbose, which can be -overridden with 'make V=0'. - -Particular systems -================== - - On HP-UX, the default C compiler is not ANSI C compatible. If GNU -CC is not installed, it is recommended to use the following options in -order to use an ANSI C compiler: - - ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" - -and if that doesn't work, install pre-built binaries of GCC for HP-UX. - - HP-UX 'make' updates targets which have the same time stamps as -their prerequisites, which makes it generally unusable when shipped -generated files such as 'configure' are involved. Use GNU 'make' -instead. - - On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot -parse its '' header file. The option '-nodtk' can be used as -a workaround. If GNU CC is not installed, it is therefore recommended -to try - - ./configure CC="cc" - -and if that doesn't work, try - - ./configure CC="cc -nodtk" - - On Solaris, don't put '/usr/ucb' early in your 'PATH'. This -directory contains several dysfunctional programs; working variants of -these programs are available in '/usr/bin'. So, if you need '/usr/ucb' -in your 'PATH', put it _after_ '/usr/bin'. - - On Haiku, software installed for all users goes in '/boot/common', -not '/usr/local'. It is recommended to use the following options: - - ./configure --prefix=/boot/common - -Specifying the System Type -========================== - - There may be some features 'configure' cannot figure out -automatically, but needs to determine by the type of machine the package -will run on. Usually, assuming the package is built to be run on the -_same_ architectures, 'configure' can figure that out, but if it prints -a message saying it cannot guess the machine type, give it the -'--build=TYPE' option. TYPE can either be a short name for the system -type, such as 'sun4', or a canonical name which has the form: - - CPU-COMPANY-SYSTEM - -where SYSTEM can have one of these forms: - - OS - KERNEL-OS - - See the file 'config.sub' for the possible values of each field. If -'config.sub' isn't included in this package, then this package doesn't -need to know the machine type. - - If you are _building_ compiler tools for cross-compiling, you should -use the option '--target=TYPE' to select the type of system they will -produce code for. - - If you want to _use_ a cross compiler, that generates code for a -platform different from the build platform, you should specify the -"host" platform (i.e., that on which the generated programs will -eventually be run) with '--host=TYPE'. - -Sharing Defaults -================ - - If you want to set default values for 'configure' scripts to share, -you can create a site shell script called 'config.site' that gives -default values for variables like 'CC', 'cache_file', and 'prefix'. -'configure' looks for 'PREFIX/share/config.site' if it exists, then -'PREFIX/etc/config.site' if it exists. Or, you can set the -'CONFIG_SITE' environment variable to the location of the site script. -A warning: not all 'configure' scripts look for a site script. - -Defining Variables -================== - - Variables not defined in a site shell script can be set in the -environment passed to 'configure'. However, some packages may run -configure again during the build, and the customized values of these -variables may be lost. In order to avoid this problem, you should set -them in the 'configure' command line, using 'VAR=value'. For example: - - ./configure CC=/usr/local2/bin/gcc - -causes the specified 'gcc' to be used as the C compiler (unless it is -overridden in the site shell script). - -Unfortunately, this technique does not work for 'CONFIG_SHELL' due to -an Autoconf limitation. Until the limitation is lifted, you can use -this workaround: - - CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash - -'configure' Invocation -====================== - - 'configure' recognizes the following options to control how it -operates. - -'--help' -'-h' - Print a summary of all of the options to 'configure', and exit. - -'--help=short' -'--help=recursive' - Print a summary of the options unique to this package's - 'configure', and exit. The 'short' variant lists options used - only in the top level, while the 'recursive' variant lists options - also present in any nested packages. - -'--version' -'-V' - Print the version of Autoconf used to generate the 'configure' - script, and exit. - -'--cache-file=FILE' - Enable the cache: use and save the results of the tests in FILE, - traditionally 'config.cache'. FILE defaults to '/dev/null' to - disable caching. - -'--config-cache' -'-C' - Alias for '--cache-file=config.cache'. - -'--quiet' -'--silent' -'-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to '/dev/null' (any error - messages will still be shown). - -'--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - 'configure' can determine that directory automatically. - -'--prefix=DIR' - Use DIR as the installation prefix. *note Installation Names:: - for more details, including other options available for fine-tuning - the installation locations. - -'--no-create' -'-n' - Run the configure checks, but stop before creating any output - files. - -'configure' also accepts some other, not widely useful, options. Run -'configure --help' for more details. diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index c55c5a3..0000000 --- a/Makefile.am +++ /dev/null @@ -1,89 +0,0 @@ -# global flags - -COMMANDS = df dl get ls test export mkdir put reg rm copy - -ACLOCAL_AMFLAGS = -I m4 - -AM_CFLAGS = \ - $(GLIB_CFLAGS) \ - $(OPENSSL_CFLAGS) \ - $(LIBCURL_CFLAGS) \ - -DG_LOG_DOMAIN=\"Mega\" \ - -I$(srcdir)/lib \ - -I$(srcdir) \ - -std=c99 - -LDADD = \ - $(GLIB_LIBS) \ - $(OPENSSL_LIBS) \ - $(LIBCURL_LIBS) - -# tools - -EXTRA_DIST = lib/sjson.c - -bin_PROGRAMS = megatools - -megatools_SOURCES = \ - lib/sjson.gen.c \ - lib/sjson.h \ - lib/http.c \ - lib/http.h \ - lib/mega.c \ - lib/mega.h \ - lib/tools.c \ - lib/tools.h \ - lib/alloc.h \ - lib/mega.h \ - tools/df.c \ - tools/dl.c \ - tools/get.c \ - tools/ls.c \ - tools/test.c \ - tools/export.c \ - tools/mkdir.c \ - tools/put.c \ - tools/reg.c \ - tools/rm.c \ - tools/copy.c \ - tools/shell.c \ - tools/shell.h - -if INSTALL_COMPAT_SYMLINKS - -install-exec-hook: - cd $(DESTDIR)$(bindir) && \ - for cmd in $(COMMANDS) ; do \ - rm -f mega$$cmd$(EXEEXT) ; \ - $(LN_S) megatools$(EXEEXT) mega$$cmd$(EXEEXT) ; \ - done - -endif - -# docs - -MAN1 = megatools $(addprefix megatools-,$(COMMANDS)) -MAN5 = megarc - -man1_MANS = $(addprefix docs/,$(addsuffix .1, $(MAN1))) -man5_MANS = $(addprefix docs/,$(addsuffix .5, $(MAN5))) - -EXTRA_DIST += $(man1_MANS) $(man5_MANS) - -EXTRA_DIST += LICENSE contrib/bash-completion/megatools - -doc_DATA = LICENSE NEWS TODO README INSTALL - -EXTRA_DIST += \ - docs/auth-options.txt \ - docs/basic-options.txt \ - docs/download-options.txt \ - docs/footer.txt \ - docs/megarc.txt \ - $(addsuffix .txt,$(addprefix docs/megatools-,$(COMMANDS))) \ - docs/megatools.txt \ - docs/network-options.txt \ - docs/remote-paths.txt \ - docs/upload-options.txt \ - docs/asciidoc.conf \ - docs/Makefile diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 7dd11e5..0000000 --- a/autogen.sh +++ /dev/null @@ -1,25 +0,0 @@ -#! /bin/sh - -srcdir=`dirname $0` -test -z "$srcdir" && srcdir=. - -ORIGDIR=`pwd` -cd $srcdir - -mkdir -p m4 - -autoreconf -v --install || exit 1 -cd $ORIGDIR || exit $? - -$srcdir/configure --enable-maintainer-mode --enable-warnings "$@" - -cat << EOF -========================================================================= -| WARNING You're building from GIT code | -========================================================================= -| - Don't! git is for developers, release tarballs are for end users. | -| Get them here: https://megatools.megous.com/builds/ | -| - Read the README for build instructions! | -| - Random checkouts from git are not tested. | -========================================================================= -EOF \ No newline at end of file diff --git a/configure.ac b/configure.ac deleted file mode 100644 index cb51714..0000000 --- a/configure.ac +++ /dev/null @@ -1,71 +0,0 @@ -AC_PREREQ(2.60) -AC_INIT([megatools],[1.11.0-git],[megous@megous.com],[megatools]) -AC_CONFIG_SRCDIR([Makefile.am]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_HEADER([config.h]) -AM_INIT_AUTOMAKE([silent-rules foreign subdir-objects -Wno-portability]) -AM_MAINTAINER_MODE -AM_SILENT_RULES([yes]) - -AC_PROG_CC -#AC_PROG_RANLIB -AM_PROG_CC_C_O -AC_PROG_LN_S -AC_HEADER_STDC - -AC_LIBTOOL_WIN32_DLL -AM_PROG_LIBTOOL - -# Define requirements - -GLIB_VERSION="2.32.0" -LIBCURL_REQUIRES="libcurl" -OPENSSL_REQUIRES="openssl" - -# check for glib/gio -PKG_CHECK_MODULES(GLIB, [gio-2.0 >= $GLIB_VERSION]) -AC_SUBST(GLIB_CFLAGS) -AC_SUBST(GLIB_LIBS) - -# check openssl -PKG_CHECK_MODULES(OPENSSL, [$OPENSSL_REQUIRES]) -AC_SUBST(OPENSSL_CFLAGS) -AC_SUBST(OPENSSL_LIBS) - -# check libcurl -PKG_CHECK_MODULES(LIBCURL, [$LIBCURL_REQUIRES]) -AC_SUBST(LIBCURL_CFLAGS) -AC_SUBST(LIBCURL_LIBS) - -# enable compatibility symlinks -AC_ARG_ENABLE([compat-symlinks], AC_HELP_STRING([--enable-compat-symlinks], [Install symlinks for compatibility with old megatools commands (megals, megacopy, megadl, ...).])) -AM_CONDITIONAL([INSTALL_COMPAT_SYMLINKS], [test "x$enable_compat_symlinks" = "xyes"]) - -# enable dev compiler warnings -AC_ARG_ENABLE([warnings], AC_HELP_STRING([--enable-warnings], [Build with compiler warnings enabled.])) -AS_IF([test "x$enable_warnings" = "xyes"], [ - CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-unused-local-typedefs -Wno-sign-compare -Wno-pointer-sign -Wno-missing-field-initializers" - - AS_IF([$CC --version | head -n1 | grep '(GCC) 4\.8' &>/dev/null], [CFLAGS="$CFLAGS -Wno-unused-local-typedefs"]) -], [ - CFLAGS="$CFLAGS -Wno-pointer-sign -Wno-unused-variable" - enable_warnings=no -]) - -AC_CONFIG_FILES([ - Makefile -]) - -AC_OUTPUT - -cat << EOF - -Configured features: - - warnings: $enable_warnings - -Run make now. - -NOTE: On FreeBSD, you need to use GNU make (gmake) - -EOF diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 66bb446..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# build docs - -VERSION = 1.10.3 -COMMANDS = df dl get ls test export mkdir put reg rm copy - -COMMON_DEPS = \ - asciidoc.conf \ - footer.txt \ - $(wildcard *-options.txt) \ - remote-paths.txt - -all: - -define MAN_template = -$(1).$(2): $(1).txt $(COMMON_DEPS) - a2x --asciidoc-opts="-f asciidoc.conf -o $$@" --destination-dir . -f manpage $$< - test $$(subst -,_,$$@) = $$@ || mv -f $$(subst -,_,$$@) $$@ - @sed -i 's/megatools_/megatools-/' $$@ - @sed -i 's/\[FIXME: manual]/Megatools Manual/' $$@ - @sed -i 's/\[FIXME: source]/megatools $(VERSION)/' $$@ - -all: $(1).$(2) -clean-$(1).$(2): - rm $(1).$(2) -clean: clean-$(1).$(2) -endef - -$(foreach cmd,$(COMMANDS),$(eval $(call MAN_template,megatools-$(cmd),1))) -$(eval $(call MAN_template,megatools,1)) -$(eval $(call MAN_template,megarc,5)) - diff --git a/install-symlinks.sh b/install-symlinks.sh new file mode 100644 index 0000000..ba6efb2 --- /dev/null +++ b/install-symlinks.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +bindir="$1" + +mkdir -p "${DESTDIR}/${MESON_INSTALL_PREFIX}/$bindir" + +for cmd in df dl get ls test export mkdir put reg rm copy +do + ln -snf megatools "${DESTDIR}/${MESON_INSTALL_PREFIX}/$bindir/mega$cmd" +done diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..7f3b05f --- /dev/null +++ b/meson.build @@ -0,0 +1,118 @@ +project('megatools', 'c', + version: '1.11.0', + default_options: [ + 'c_std=gnu99', + ], + meson_version : '>= 0.46.0', + license: 'GPLv3') + +cc = meson.get_compiler('c') +add_global_arguments('-Wno-unused', '-Wno-pointer-sign', language: 'c') + +deps = [ + dependency('threads'), + dependency('gio-2.0', version: '>=2.32.0'), + dependency('libcurl'), + dependency('openssl'), +] + +#if host_machine.system() == 'windows' +# deps += [cc.find_library('wsock32')] +#endif + +# targets + +cdata = configuration_data() +cdata.set_quoted('VERSION', meson.project_version()) +cfile = configure_file(configuration: cdata, output: 'config.h') + +commands = ['df', 'dl', 'get', 'ls', 'test', 'export', 'mkdir', 'put', 'reg', 'rm', 'copy'] + +executable('megatools', + 'lib/sjson.gen.c', + 'lib/http.c', + 'lib/mega.c', + 'lib/tools.c', + 'tools/df.c', + 'tools/dl.c', + 'tools/get.c', + 'tools/ls.c', + 'tools/test.c', + 'tools/export.c', + 'tools/mkdir.c', + 'tools/put.c', + 'tools/reg.c', + 'tools/rm.c', + 'tools/copy.c', + 'tools/shell.c', + dependencies: deps, + include_directories: include_directories('lib', 'tools', '.'), + install: true +) + +#XXX: contrib/bash-completion/megatools + +if get_option('symlinks') or true + meson.add_install_script('install-symlinks.sh', get_option('bindir')) +endif + +# docs + +install_data(['README', 'NEWS', 'TODO', 'LICENSE'], + install_dir: join_paths(get_option('datadir'), 'doc', meson.project_name()), +) + +manpages = [ + ['megatools', '1'], + ['megarc', '5'], +] + +foreach cmd: commands + manpages += [['megatools-' + cmd, '1']] +endforeach + +# build docs + +asciidoc = find_program('asciidoc') +db2x_xsltproc = find_program('db2x_xsltproc') +db2x_manxml = find_program('db2x_manxml') +enable_manpages = asciidoc.found() and db2x_xsltproc.found() and db2x_manxml.found() + +if enable_manpages and get_option('man') + +foreach mp: manpages + mandirn = join_paths(get_option('mandir'), 'man' + mp[1]) + + docb = custom_target(mp[0] + '-db', + command: [asciidoc, '-f', files('docs/asciidoc.conf'), '-o', '@OUTPUT@', '-b', 'docbook', '-d', 'manpage', '@INPUT@'], + output: [mp[0] + '.xml'], + input: ['docs/' + mp[0] + '.txt'], + depend_files: [ + 'docs/asciidoc.conf', + 'docs/footer.txt', + 'docs/auth-options.txt', + 'docs/basic-options.txt', + 'docs/download-options.txt', + 'docs/network-options.txt', + 'docs/upload-options.txt', + 'docs/remote-paths.txt', + ], + ) + + mxml = custom_target(mp[0] + '-mxml', + command: [db2x_xsltproc, '-s', 'man', '--param', 'xref-on-link=0', '@INPUT@', '-o', '@OUTPUT@'], + output: [mp[0] + '.mxml'], + input: [docb], + ) + + manx = custom_target(mp[0] + '-man', + command: [db2x_manxml, '--to-stdout', '@INPUT@'], + capture: true, + output: [mp[0] + '.' + mp[1]], + input: [mxml], + install: true, + install_dir: mandirn, + ) +endforeach + +endif \ No newline at end of file diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..999bcaa --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,11 @@ +option('symlinks', + type: 'boolean', + value: false, + description: 'Install symlinks for compatibility with old megatools commands (megals, megacopy, megadl, ...)' +) + +option('man', + type: 'boolean', + value: true, + description: 'Build and install manual pages.' +) From 2951a35ddc6048dd97bf3a266e752be524b480ac Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 11 Nov 2019 22:43:35 +0100 Subject: [PATCH 09/33] Make doc generator programs optional --- meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 7f3b05f..0501a23 100644 --- a/meson.build +++ b/meson.build @@ -73,9 +73,9 @@ endforeach # build docs -asciidoc = find_program('asciidoc') -db2x_xsltproc = find_program('db2x_xsltproc') -db2x_manxml = find_program('db2x_manxml') +asciidoc = find_program('asciidoc', required: false) +db2x_xsltproc = find_program('db2x_xsltproc', required: false) +db2x_manxml = find_program('db2x_manxml', required: false) enable_manpages = asciidoc.found() and db2x_xsltproc.found() and db2x_manxml.found() if enable_manpages and get_option('man') From 033f573262b7813a0bd618bc2974d753c4f52f99 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sat, 4 Apr 2020 04:02:55 +0200 Subject: [PATCH 10/33] dl: Add support for new link formats - make it slightly more generic so that new mega.nz inventions can be incorporated more easily in the future. --- tools/dl.c | 109 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 37 deletions(-) diff --git a/tools/dl.c b/tools/dl.c index 1e4efd2..636b0fc 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -322,10 +322,69 @@ static gboolean dl_sync_dir_choose(GFile *local_dir) return status; } +enum { + LINK_NONE, + LINK_FILE, + LINK_FOLDER, +}; + +struct mega_link +{ + int type; + gchar *key; + gchar *handle; + gchar *specific; +}; + +static struct { + const char* pattern; + int type; + GRegex* re; +} link_regexes[] = { + { "^https?://mega(?:\\.co)?\\.nz/#!([a-z0-9_-]{8})!([a-z0-9_-]{43})$", LINK_FILE }, + { "^https?://mega\\.nz/file/([a-z0-9_-]{8})#([a-z0-9_-]{43})$", LINK_FILE }, + { "^https?://mega(?:\\.co)?\\.nz/#F!([a-z0-9_-]{8})!([a-z0-9_-]{22})(?:[!?]([a-z0-9_-]{8}))?$", LINK_FOLDER }, + { "^https?://mega\\.nz/folder/([a-z0-9_-]{8})#([a-z0-9_-]{22})$", LINK_FOLDER }, +}; + +static gboolean parse_link(const char* url, struct mega_link* l) +{ + GMatchInfo *m = NULL; + int i; + + for (i = 0; i < G_N_ELEMENTS(link_regexes); i++) { + if (!link_regexes[i].re) { + link_regexes[i].re = g_regex_new(link_regexes[i].pattern, G_REGEX_CASELESS, 0, NULL); + g_assert(link_regexes[i].re != NULL); + } + + if (g_regex_match(link_regexes[i].re, url, 0, &m)) { + l->type = link_regexes[i].type; + l->handle = g_match_info_fetch(m, 1); + l->key = g_match_info_fetch(m, 2); + l->specific = g_match_info_fetch(m, 3); + + g_clear_pointer(&m, g_match_info_unref); + return TRUE; + } + + g_clear_pointer(&m, g_match_info_unref); + } + + return FALSE; +} + +static void free_link(struct mega_link* l) +{ + g_free(l->key); + g_free(l->handle); + g_free(l->specific); + memset(l, 0, sizeof(*l)); +} + static int dl_main(int ac, char *av[]) { gc_error_free GError *local_err = NULL; - gc_regex_unref GRegex *file_regex = NULL, *folder_regex = NULL; gint i; int status = 0; @@ -353,17 +412,6 @@ static int dl_main(int ac, char *av[]) return 1; } - // prepare link parsers - - file_regex = g_regex_new("^https?://mega(?:\\.co)?\\.nz/#!([a-z0-9_-]{8})!([a-z0-9_-]{43})$", G_REGEX_CASELESS, - 0, NULL); - g_assert(file_regex != NULL); - - folder_regex = - g_regex_new("^https?://mega(?:\\.co)?\\.nz/#F!([a-z0-9_-]{8})!([a-z0-9_-]{22})(?:[!?]([a-z0-9_-]{8}))?$", - G_REGEX_CASELESS, 0, NULL); - g_assert(folder_regex != NULL); - // create session s = tool_start_session(TOOL_SESSION_OPEN | TOOL_SESSION_AUTH_ONLY | TOOL_SESSION_AUTH_OPTIONAL); @@ -376,28 +424,17 @@ static int dl_main(int ac, char *av[]) // process links for (i = 1; i < ac; i++) { - gc_match_info_unref GMatchInfo *m1 = NULL; - gc_match_info_unref GMatchInfo *m2 = NULL; - gc_free gchar *key = NULL; - gc_free gchar *handle = NULL; - gc_free gchar *specific = NULL; gc_free gchar *link_utf8 = tool_convert_filename(av[i], FALSE); gc_free gchar *link = g_uri_unescape_string(link_utf8, NULL); + struct mega_link l; - // Codes can move to tools.c (tool convert filename function) - link = g_uri_unescape_string(link, NULL); - /* - INPUT: https://mega.nz/#%21H2pDmAgC!isXGprskZbLP4KnLNuNHcbI279s6FnLcsj8Vydm_sio - OUTPUT: https://mega.nz/#!H2pDmAgC!isXGprskZbLP4KnLNuNHcbI279s6FnLcsj8Vydm_sio - */ - // link = g_uri_unescape_string("https://mega.nz/#%21H2pDmAgC!isXGprskZbLP4KnLNuNHcbI279s6FnLcsj8Vydm_sio", NULL); - - if (g_regex_match(file_regex, link, 0, &m1)) { - handle = g_match_info_fetch(m1, 1); - key = g_match_info_fetch(m1, 2); - + if (!parse_link(link, &l)) { + g_printerr("WARNING: Skipping invalid Mega download link: %s\n", link); + continue; + } + if (l.type == LINK_FILE) { // perform download - if (!mega_session_dl_compat(s, handle, key, opt_stream ? NULL : opt_path, &local_err)) { + if (!mega_session_dl_compat(s, l.handle, l.key, opt_stream ? NULL : opt_path, &local_err)) { if (!opt_noprogress && tool_is_stdout_tty()) g_print("\r" ESC_CLREOL "\n"); g_printerr("ERROR: Download failed for '%s': %s\n", link, local_err->message); @@ -413,19 +450,15 @@ static int dl_main(int ac, char *av[]) if (opt_print_names) g_print("%s\n", cur_file); } - } else if (g_regex_match(folder_regex, link, 0, &m2)) { + } else if (l.type == LINK_FOLDER) { if (opt_stream) { g_printerr("ERROR: Can't stream from a directory!\n"); tool_fini(s); return 1; } - handle = g_match_info_fetch(m2, 1); - key = g_match_info_fetch(m2, 2); - specific = g_match_info_fetch(m2, 3); - // perform download - if (!mega_session_open_exp_folder(s, handle, key, specific, &local_err)) { + if (!mega_session_open_exp_folder(s, l.handle, l.key, l.specific, &local_err)) { g_printerr("ERROR: Can't open folder '%s': %s\n", link, local_err->message); g_clear_error(&local_err); status = 1; @@ -463,8 +496,10 @@ static int dl_main(int ac, char *av[]) g_slist_free(l); } } else { - g_printerr("WARNING: Skipping invalid Mega download link: %s\n", link); + g_printerr("WARNING: Skipping invalid Mega download link type: %s\n", link); } + + free_link(&l); } tool_fini(s); From 9c8ba854c2aad92b80ebe6b468dc295c6937cd01 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Fri, 1 May 2020 11:58:26 +0200 Subject: [PATCH 11/33] dl: Support new link format for individual files inside folders --- tools/dl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/dl.c b/tools/dl.c index 636b0fc..e25c759 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -344,6 +344,7 @@ static struct { { "^https?://mega(?:\\.co)?\\.nz/#!([a-z0-9_-]{8})!([a-z0-9_-]{43})$", LINK_FILE }, { "^https?://mega\\.nz/file/([a-z0-9_-]{8})#([a-z0-9_-]{43})$", LINK_FILE }, { "^https?://mega(?:\\.co)?\\.nz/#F!([a-z0-9_-]{8})!([a-z0-9_-]{22})(?:[!?]([a-z0-9_-]{8}))?$", LINK_FOLDER }, + { "^https?://mega\\.nz/folder/([a-z0-9_-]{8})#([a-z0-9_-]{22})/file/([a-z0-9_-]{8})$", LINK_FOLDER }, { "^https?://mega\\.nz/folder/([a-z0-9_-]{8})#([a-z0-9_-]{22})$", LINK_FOLDER }, }; From 2a9bde919a3b394d29d5b9c046a92ed359229b69 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sat, 2 May 2020 14:44:15 +0200 Subject: [PATCH 12/33] Add contributed support for v2 login flow Thanks to Anonymous :) --- lib/mega.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/lib/mega.c b/lib/mega.c index 84422c0..4e6b58d 100644 --- a/lib/mega.c +++ b/lib/mega.c @@ -2310,19 +2310,78 @@ gboolean mega_session_open(struct mega_session *s, const gchar *un, const gchar if (!is_loggedin) { gc_free gchar *un_lower = g_ascii_strdown(un, -1); - gc_free gchar *uh = make_username_hash(un_lower, s->password_key); g_free(s->sid); s->sid = NULL; - // login user - gc_free gchar *login_node = - api_call(s, 'o', NULL, &local_err, "[{a:us, user:%s, uh:%s}]", un_lower, uh); - if (!login_node) { + // pre login + gc_free gchar *pre_login_node = + api_call(s, 'o', NULL, &local_err, "[{a:us0, user:%s}]", un_lower); + if (!pre_login_node) { g_propagate_error(err, local_err); return FALSE; } + gint user_v = s_json_get_member_int(pre_login_node, "v", 1); + + gc_free gchar *login_node; + + if (user_v == 2) { + + // salt + gc_free gchar *b64_salt = s_json_get_member_string(pre_login_node, "s"); + + if (b64_salt == NULL) { + g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Invalid salt"); + return FALSE; + } + + gsize len; + gc_free gchar *salt = base64urldecode(b64_salt, &len); + + if (salt == NULL) { + g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Invalid salt: Unable to decode"); + return FALSE; + } + + // derive key + guchar key[32]; + + PKCS5_PBKDF2_HMAC(pw, strlen(pw), + salt, strlen(salt), + 100000, EVP_sha512(), + sizeof(key), key); + + // Derived key contains master key (s->password_key) (0-16) and password hash (16-32) + const char *authKey = key + 16; + + gc_free gchar *b64_authKey = base64urlencode(authKey, 16); + + // login user + login_node = + api_call(s, 'o', NULL, &local_err, "[{a:us, user:%s, uh:%s}]", un_lower, b64_authKey); + if (!login_node) { + g_propagate_error(err, local_err); + return FALSE; + } + + // set s->password_key + // Derived key contains master key (s->password_key) (0-16) and password hash (16-32) + memcpy(s->password_key, key, 16); + //s->password_key[16] = '\0'; + + } else { + gc_free gchar *uh = make_username_hash(un_lower, s->password_key); + + // login user + login_node = + api_call(s, 'o', NULL, &local_err, "[{a:us, user:%s, uh:%s}]", un_lower, uh); + if (!login_node) { + g_propagate_error(err, local_err); + return FALSE; + } + } + gc_free gchar *login_k = s_json_get_member_string(login_node, "k"); gc_free gchar *login_privk = s_json_get_member_string(login_node, "privk"); gc_free gchar *login_csid = s_json_get_member_string(login_node, "csid"); From 1a07837281ad8ab68675946822b9d066c2de8206 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sun, 3 May 2020 15:38:22 +0200 Subject: [PATCH 13/33] Cleanup login v2 support and fix session caching --- lib/mega.c | 254 ++++++++++++++++++++++++++++++---------------------- lib/mega.h | 5 +- lib/tools.c | 32 ++----- 3 files changed, 158 insertions(+), 133 deletions(-) diff --git a/lib/mega.c b/lib/mega.c index 4e6b58d..bae6ed4 100644 --- a/lib/mega.c +++ b/lib/mega.c @@ -109,7 +109,9 @@ struct mega_session { gchar *rid; GHashTable *api_url_params; + gchar *password_salt_v2; /* as returned from mega.nz (base64 string) */ guchar *password_key; + guchar *password_key_save; /* password key for session saver */ guchar *master_key; struct rsa_key rsa_key; @@ -2281,147 +2283,173 @@ gboolean mega_session_open_exp_folder(struct mega_session *s, const gchar *n, co // }}} // {{{ mega_session_open -gboolean mega_session_open(struct mega_session *s, const gchar *un, const gchar *pw, const gchar *sid, GError **err) +// this has side effect of the current session being closed +static gboolean mega_session_load(struct mega_session *s, + const gchar *un, const gchar *pw, gint max_age, + gchar **last_sid, gchar** last_pwsalt_v2, + GError **err); + +gboolean mega_session_open(struct mega_session *s, const gchar *un, const gchar *pw, + gint max_age, gboolean *is_new_session, GError **err) { GError *local_err = NULL; gboolean is_loggedin = FALSE; + gc_free gchar* sid = NULL; + gc_free gchar* pwsalt_v2 = NULL; + gint login_variant = 0; + gc_free gchar *un_lower = NULL; + gc_free gchar *uh = NULL; g_return_val_if_fail(s != NULL, FALSE); g_return_val_if_fail(un != NULL, FALSE); g_return_val_if_fail(pw != NULL, FALSE); g_return_val_if_fail(err == NULL || *err == NULL, FALSE); - mega_session_close(s); + // try to load cached session data first + if (mega_session_load(s, un, pw, max_age, &sid, &pwsalt_v2, NULL)) { + *is_new_session = FALSE; + return TRUE; + } - //g_print("%s %s %s\n", un, pw, sid); + *is_new_session = TRUE; - // make password key - g_free(s->password_key); - s->password_key = make_password_key(pw); + // session load failed, clean session data + mega_session_close(s); + s->password_key_save = make_password_key(pw); + un_lower = g_ascii_strdown(un, -1); - // if we have existing session id, just check with the server if session is - // active, and download keys and user info + // now if mega_session_load found a previous expired cache file, it will + // return sid and pwsalt_v2 that we can try to re-use if (sid) { - g_free(s->sid); - s->sid = g_strdup(sid); - - is_loggedin = mega_session_get_user(s, NULL); - } - - if (!is_loggedin) { - gc_free gchar *un_lower = g_ascii_strdown(un, -1); + // if load_session returned sid, existence of pwsalt_v2 is + // enough to determine login variant + login_variant = pwsalt_v2 ? 2 : 0; g_free(s->sid); - s->sid = NULL; + s->sid = g_strdup(sid); - // pre login - gc_free gchar *pre_login_node = - api_call(s, 'o', NULL, &local_err, "[{a:us0, user:%s}]", un_lower); + g_free(s->password_salt_v2); + s->password_salt_v2 = g_strdup(pwsalt_v2); + } else { + // no previous session data found, we need to call us0 to determine the login + // variant in use + gc_free gchar *pre_login_node = api_call(s, 'o', NULL, &local_err, "[{a:us0, user:%s}]", un_lower); if (!pre_login_node) { g_propagate_error(err, local_err); return FALSE; } - gint user_v = s_json_get_member_int(pre_login_node, "v", 1); - - gc_free gchar *login_node; - - if (user_v == 2) { - - // salt - gc_free gchar *b64_salt = s_json_get_member_string(pre_login_node, "s"); - - if (b64_salt == NULL) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Invalid salt"); + login_variant = s_json_get_member_int(pre_login_node, "v", 0); + if (login_variant == 2) { + // get the password salt for the login v2 + g_free(pwsalt_v2); + pwsalt_v2 = s_json_get_member_string(pre_login_node, "s"); + if (pwsalt_v2 == NULL) { + g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Missing salt (v2)"); return FALSE; } - gsize len; - gc_free gchar *salt = base64urldecode(b64_salt, &len); - - if (salt == NULL) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Invalid salt: Unable to decode"); - return FALSE; - } + g_free(s->password_salt_v2); + s->password_salt_v2 = g_strdup(pwsalt_v2); + } + } - // derive key - guchar key[32]; + // session is not valid or is missing, we need to login again via 'us' + // call - PKCS5_PBKDF2_HMAC(pw, strlen(pw), - salt, strlen(salt), - 100000, EVP_sha512(), - sizeof(key), key); + if (login_variant == 2) { + // login variant 2: + // - uses PKCS5_PBKDF2_HMAC which requires a salt that is generated during registration + // and stored on the server (also returned by 'us0' call in the 's' field) + // - PKCS5_PBKDF2_HMAC produces a 32byte value: + // - first half is a password key + // - second half is user hash for the 'us' call - // Derived key contains master key (s->password_key) (0-16) and password hash (16-32) - const char *authKey = key + 16; + // decode salt from base64 + gsize salt_len; + gc_free gchar *salt = base64urldecode(pwsalt_v2, &salt_len); + if (salt == NULL) { + g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Failed to decode salt (v2)"); + return FALSE; + } - gc_free gchar *b64_authKey = base64urlencode(authKey, 16); + // derive password key and user hash + guchar key[32]; + PKCS5_PBKDF2_HMAC(pw, strlen(pw), + salt, salt_len, + 100000, EVP_sha512(), + sizeof(key), key); - // login user - login_node = - api_call(s, 'o', NULL, &local_err, "[{a:us, user:%s, uh:%s}]", un_lower, b64_authKey); - if (!login_node) { - g_propagate_error(err, local_err); - return FALSE; - } + g_free(s->password_key); + s->password_key = g_memdup(key, 16); - // set s->password_key - // Derived key contains master key (s->password_key) (0-16) and password hash (16-32) - memcpy(s->password_key, key, 16); - //s->password_key[16] = '\0'; + uh = base64urlencode(key + 16, 16); + } else { + // make password key and user hash for v1 login + g_free(s->password_key); + s->password_key = make_password_key(pw); - } else { - gc_free gchar *uh = make_username_hash(un_lower, s->password_key); + uh = make_username_hash(un_lower, s->password_key); + } - // login user - login_node = - api_call(s, 'o', NULL, &local_err, "[{a:us, user:%s, uh:%s}]", un_lower, uh); - if (!login_node) { - g_propagate_error(err, local_err); - return FALSE; - } - } + if (uh == NULL) { + g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Faield to encode user hash"); + return FALSE; + } - gc_free gchar *login_k = s_json_get_member_string(login_node, "k"); - gc_free gchar *login_privk = s_json_get_member_string(login_node, "privk"); - gc_free gchar *login_csid = s_json_get_member_string(login_node, "csid"); + if (sid) { + // try to fetch user data, this will verify the session id + if (mega_session_get_user(s, NULL)) + return TRUE; - // decrypt master key - gc_free guchar *master_key = b64_aes128_decrypt(login_k, s->password_key, NULL); - if (!master_key) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Can't read master key during login"); - return FALSE; - } + g_free(s->sid); + s->sid = NULL; + } - // decrypt private key with master key - struct rsa_key privk; - memset(&privk, 0, sizeof(privk)); - if (!b64_aes128_decrypt_privk(login_privk, master_key, &privk)) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Can't read private key during login"); - rsa_key_free(&privk); - return FALSE; - } + // login user + gc_free gchar *login_node = api_call(s, 'o', NULL, &local_err, "[{a:us, user:%s, uh:%s}]", un_lower, uh); + if (!login_node) { + g_propagate_error(err, local_err); + return FALSE; + } - // decrypt session id - gsize sid_len = 0; - gc_free guchar *sid = b64_rsa_decrypt(login_csid, &privk, &sid_len); - if (!sid || sid_len < 43) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Can't read session id during login"); - rsa_key_free(&privk); - return FALSE; - } + gc_free gchar *login_k = s_json_get_member_string(login_node, "k"); + gc_free gchar *login_privk = s_json_get_member_string(login_node, "privk"); + gc_free gchar *login_csid = s_json_get_member_string(login_node, "csid"); - // save session id - g_free(s->sid); - s->sid = base64urlencode(sid, 43); + // decrypt master key + gc_free guchar *master_key = b64_aes128_decrypt(login_k, s->password_key, NULL); + if (!master_key) { + g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Can't read master key during login"); + return FALSE; + } - // cleanup + // decrypt private key with master key + struct rsa_key privk; + memset(&privk, 0, sizeof(privk)); + if (!b64_aes128_decrypt_privk(login_privk, master_key, &privk)) { + g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Can't read private key during login"); rsa_key_free(&privk); + return FALSE; + } - return mega_session_get_user(s, err); + // decrypt session id + gsize sid_len = 0; + gc_free guchar *sid_binary = b64_rsa_decrypt(login_csid, &privk, &sid_len); + if (!sid_binary || sid_len < 43) { + g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Can't read session id during login"); + rsa_key_free(&privk); + return FALSE; } - return TRUE; + // save session id + g_free(s->sid); + s->sid = base64urlencode(sid_binary, 43); + + // cleanup + rsa_key_free(&privk); + + return mega_session_get_user(s, err); } // }}} @@ -2432,6 +2460,8 @@ void mega_session_close(struct mega_session *s) g_return_if_fail(s != NULL); g_free(s->password_key); + g_free(s->password_key_save); + g_free(s->password_salt_v2); g_free(s->master_key); g_free(s->sid); rsa_key_free(&s->rsa_key); @@ -2445,6 +2475,8 @@ void mega_session_close(struct mega_session *s) g_hash_table_remove_all(s->api_url_params); s->password_key = NULL; + s->password_key_save = NULL; + s->password_salt_v2 = NULL; s->master_key = NULL; s->sid = NULL; s->user_handle = NULL; @@ -4935,6 +4967,7 @@ gboolean mega_session_save(struct mega_session *s, GError **err) s_json_gen_member_int(gen, "last_refresh", s->last_refresh); s_json_gen_member_string(gen, "sid", s->sid); + s_json_gen_member_string(gen, "password_salt_v2", s->password_salt_v2); s_json_gen_member_bytes(gen, "password_key", s->password_key, 16); s_json_gen_member_bytes(gen, "master_key", s->master_key, 16); s_json_gen_member_rsa_key(gen, "rsa_key", &s->rsa_key); @@ -4972,7 +5005,7 @@ gboolean mega_session_save(struct mega_session *s, GError **err) print_node(cache_data, "SAVE CACHE: "); gc_free gchar *tmp = g_strconcat("MEGA", cache_data, NULL); - gc_free gchar *cipher = b64_aes128_cbc_encrypt_str(tmp, s->password_key); + gc_free gchar *cipher = b64_aes128_cbc_encrypt_str(tmp, s->password_key_save); if (!g_file_set_contents(path, cipher, -1, &local_err)) { g_propagate_error(err, local_err); @@ -4985,8 +5018,10 @@ gboolean mega_session_save(struct mega_session *s, GError **err) // }}} // {{{ mega_session_load -gboolean mega_session_load(struct mega_session *s, const gchar *un, const gchar *pw, gint max_age, gchar **last_sid, - GError **err) +static gboolean mega_session_load(struct mega_session *s, + const gchar *un, const gchar *pw, gint max_age, + gchar **last_sid, gchar** last_pwsalt_v2, + GError **err) { GError *local_err = NULL; gc_free gchar *cipher = NULL; @@ -4997,6 +5032,7 @@ gboolean mega_session_load(struct mega_session *s, const gchar *un, const gchar g_return_val_if_fail(err == NULL || *err == NULL, FALSE); mega_session_close(s); + s->password_key_save = make_password_key(pw); // calculate cache file path gc_free gchar *un_lower = g_ascii_strdown(un, -1); @@ -5012,9 +5048,8 @@ gboolean mega_session_load(struct mega_session *s, const gchar *un, const gchar } // calculate password key - gc_free guchar *password_key = make_password_key(pw); gsize len = 0; - gc_free gchar *data = b64_aes128_cbc_decrypt(cipher, password_key, &len); + gc_free gchar *data = b64_aes128_cbc_decrypt(cipher, s->password_key_save, &len); if (!data || len < 4) { g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Corrupted cache file"); @@ -5047,9 +5082,13 @@ gboolean mega_session_load(struct mega_session *s, const gchar *un, const gchar // return sid value if available gc_free gchar *sid = s_json_get_member_string(cache_obj, "sid"); - if (last_sid && sid) + if (last_sid) *last_sid = g_strdup(sid); + gc_free gchar *password_salt_v2 = s_json_get_member_string(cache_obj, "password_salt_v2"); + if (last_pwsalt_v2) + *last_pwsalt_v2 = g_strdup(password_salt_v2); + // check max_age if (max_age > 0) { if (!last_refresh || ((last_refresh + max_age) < time(NULL))) { @@ -5062,8 +5101,13 @@ gboolean mega_session_load(struct mega_session *s, const gchar *un, const gchar gsize len; s->last_refresh = last_refresh; + s->sid = sid; sid = NULL; + + s->password_salt_v2 = password_salt_v2; + password_salt_v2 = NULL; + s->password_key = s_json_get_member_bytes(cache_obj, "password_key", &len); s->master_key = s_json_get_member_bytes(cache_obj, "master_key", &len); s_json_get_member_rsa_key(cache_obj, "rsa_key", &s->rsa_key); diff --git a/lib/mega.h b/lib/mega.h index 81ac1e4..dbf47ec 100644 --- a/lib/mega.h +++ b/lib/mega.h @@ -143,14 +143,11 @@ void mega_session_watch_status(struct mega_session *s, mega_status_callback cb, void mega_session_enable_previews(struct mega_session *s, gboolean enable); // this has side effect of the current session being closed -gboolean mega_session_open(struct mega_session *s, const gchar *un, const gchar *pw, const gchar *sid, GError **err); +gboolean mega_session_open(struct mega_session *s, const gchar *un, const gchar *pw, gint max_age, gboolean *is_new_session, GError **err); void mega_session_close(struct mega_session *s); const gchar *mega_session_get_sid(struct mega_session *s); gboolean mega_session_save(struct mega_session *s, GError **err); -// this has side effect of the current session being closed -gboolean mega_session_load(struct mega_session *s, const gchar *un, const gchar *pw, gint max_age, gchar **last_sid, - GError **err); gboolean mega_session_get_user(struct mega_session *s, GError **err); gboolean mega_session_refresh(struct mega_session *s, GError **err); diff --git a/lib/tools.c b/lib/tools.c index ecb35b4..37916cd 100644 --- a/lib/tools.c +++ b/lib/tools.c @@ -650,8 +650,7 @@ void tool_init(gint *ac, gchar ***av, const gchar *tool_name, GOptionEntry *tool struct mega_session *tool_start_session(ToolSessionFlags flags) { GError *local_err = NULL; - gchar *sid = NULL; - gboolean loaded = FALSE; + gboolean is_new_session; struct mega_session *s = mega_session_new(); @@ -675,29 +674,16 @@ struct mega_session *tool_start_session(ToolSessionFlags flags) goto err; } - // try to load cached session data (they are valid for 10 minutes since last - // user_get or refresh) - if (!mega_session_load(s, opt_username, opt_password, cache_timout, &sid, &local_err)) { - g_clear_error(&local_err); - - if (!mega_session_open(s, opt_username, opt_password, sid, &local_err)) { - g_printerr("ERROR: Can't login to mega.nz: %s\n", local_err->message); - goto err; - } - - if (!(flags & TOOL_SESSION_AUTH_ONLY)) { - if (!mega_session_refresh(s, &local_err)) { - g_printerr("ERROR: Can't read filesystem info from mega.nz: %s\n", local_err->message); - goto err; - } - - loaded = TRUE; - } + // open the session + if (!mega_session_open(s, opt_username, opt_password, cache_timout, &is_new_session, &local_err)) { + g_printerr("ERROR: Can't login to mega.nz: %s\n", local_err->message); + goto err; + } + if (is_new_session) mega_session_save(s, NULL); - } - if (!(flags & TOOL_SESSION_AUTH_ONLY) && opt_reload_files && !loaded) { + if (!(flags & TOOL_SESSION_AUTH_ONLY) && (opt_reload_files || is_new_session)) { if (!mega_session_refresh(s, &local_err)) { g_printerr("ERROR: Can't read filesystem info from mega.nz: %s\n", local_err->message); goto err; @@ -709,13 +695,11 @@ struct mega_session *tool_start_session(ToolSessionFlags flags) mega_session_enable_previews(s, !!opt_enable_previews); mega_session_set_resume(s, !opt_disable_resume); - g_free(sid); return s; err: mega_session_free(s); g_clear_error(&local_err); - g_free(sid); return NULL; } From 53693822191ef21b0fc9dc1ed4cddf01c9d0cd43 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sun, 3 May 2020 17:26:44 +0200 Subject: [PATCH 14/33] Bump cache format version --- lib/mega.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mega.c b/lib/mega.c index bae6ed4..30c753a 100644 --- a/lib/mega.c +++ b/lib/mega.c @@ -45,7 +45,7 @@ DEFINE_CLEANUP_FUNCTION_NULL(BN_CTX *, BN_CTX_free) DEFINE_CLEANUP_FUNCTION_NULL(BIGNUM *, BN_free) #define gc_bn_free CLEANUP(BN_free) -#define CACHE_FORMAT_VERSION 3 +#define CACHE_FORMAT_VERSION 4 gint mega_debug = 0; From 3a5af6e2b95ee2610407563c6ad31977306946ae Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 1 Jun 2020 02:07:28 +0200 Subject: [PATCH 15/33] Fix NULL pointer dereference when invoking megatools in some situations Reported by the user: > In "tools/shell.c", line 63, pointer "cmd_name" will be dereferenced as NULL > unless it is set in Line 59 when argv[0] is prefixed with "mega". Now, > megatools crashes if ran as something like "a.out". --- tools/shell.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/shell.c b/tools/shell.c index 971f6d8..db07465 100644 --- a/tools/shell.c +++ b/tools/shell.c @@ -58,10 +58,12 @@ int main(int ac, char *av[]) if (g_str_has_prefix(cmd_basename, "mega")) cmd_name = cmd_basename + 4; - // try to run a specifc if we're run via mega[.exe] - for (int i = 0; i < G_N_ELEMENTS(tools); i++) { - if (!strcmp(cmd_name, tools[i]->name)) - return tools[i]->main(ac, av); + if (cmd_name) { + // try to run a specifc if we're run via mega[.exe] + for (int i = 0; i < G_N_ELEMENTS(tools); i++) { + if (!strcmp(cmd_name, tools[i]->name)) + return tools[i]->main(ac, av); + } } if (ac > 1) { From 823a75670df0388481a14431a3a72c2f26444dc7 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 20 Jul 2020 22:51:29 +0200 Subject: [PATCH 16/33] Add file exists error type --- lib/mega.c | 12 ++++++------ lib/mega.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/mega.c b/lib/mega.c index 30c753a..3780ceb 100644 --- a/lib/mega.c +++ b/lib/mega.c @@ -5427,7 +5427,7 @@ struct mega_node *mega_session_put_compat(struct mega_session *s, const gchar *r if (node) { // reote path exists if (node->type == MEGA_NODE_FILE) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "File already exists: %s", remote_path); + g_set_error(err, MEGA_ERROR, MEGA_ERROR_EXISTS, "File already exists: %s", remote_path); return NULL; } else { // it's a directory, so we need to check if file with @@ -5439,7 +5439,7 @@ struct mega_node *mega_session_put_compat(struct mega_session *s, const gchar *r gc_free gchar *tmp = g_strconcat(remote_path, "/", file_name, NULL); node = mega_session_stat(s, tmp); if (node) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "File already exists: %s", tmp); + g_set_error(err, MEGA_ERROR, MEGA_ERROR_EXISTS, "File already exists: %s", tmp); return NULL; } } @@ -5500,7 +5500,7 @@ gboolean mega_session_get_compat(struct mega_session *s, const gchar *local_path if (g_file_query_file_type(file, 0, NULL) == G_FILE_TYPE_DIRECTORY) { gc_object_unref GFile *child = g_file_get_child(file, node->name); if (g_file_query_exists(child, NULL)) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, + g_set_error(err, MEGA_ERROR, MEGA_ERROR_EXISTS, "Local file already exists: %s/%s", local_path, node->name); return FALSE; } else { @@ -5508,7 +5508,7 @@ gboolean mega_session_get_compat(struct mega_session *s, const gchar *local_path child = NULL; } } else { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "Local file already exists: %s", + g_set_error(err, MEGA_ERROR, MEGA_ERROR_EXISTS, "Local file already exists: %s", local_path); return FALSE; } @@ -5529,7 +5529,7 @@ gboolean mega_session_dl_compat(struct mega_session *s, const gchar *handle, con file = g_file_new_for_path(local_path); if (g_file_query_exists(file, NULL)) { if (g_file_query_file_type(file, 0, NULL) != G_FILE_TYPE_DIRECTORY) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, "File already exists: %s", local_path); + g_set_error(err, MEGA_ERROR, MEGA_ERROR_EXISTS, "File already exists: %s", local_path); return FALSE; } else { parent_dir = file; @@ -5557,7 +5557,7 @@ gboolean mega_session_dl_compat(struct mega_session *s, const gchar *handle, con file = g_file_get_child(parent_dir, params.node_name); if (g_file_query_exists(file, NULL)) { - g_set_error(err, MEGA_ERROR, MEGA_ERROR_OTHER, + g_set_error(err, MEGA_ERROR, MEGA_ERROR_EXISTS, "Local file already exists: %s/%s", local_path, params.node_name); mega_download_data_free(¶ms); return FALSE; diff --git a/lib/mega.h b/lib/mega.h index dbf47ec..3e8ca69 100644 --- a/lib/mega.h +++ b/lib/mega.h @@ -29,6 +29,7 @@ enum { MEGA_ERROR_NO_HANDLE, + MEGA_ERROR_EXISTS, MEGA_ERROR_OTHER }; From 9eedb31d932776d2b89d5f53f056bdd976c71962 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 20 Jul 2020 22:57:22 +0200 Subject: [PATCH 17/33] Return status = 2 if uploaded file already exists Only the status for the last failure is returned. --- tools/put.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/put.c b/tools/put.c index 11743ff..56d9679 100644 --- a/tools/put.c +++ b/tools/put.c @@ -71,10 +71,14 @@ static int put_main(int ac, char *av[]) if (!opt_noprogress && tool_is_stdout_tty()) g_print("\r" ESC_CLREOL "\n"); + if (g_error_matches(local_err, MEGA_ERROR, MEGA_ERROR_EXISTS)) { + status = 2; + } else { + status = 1; + } + g_printerr("ERROR: Upload failed for '%s': %s\n", path, local_err->message); g_clear_error(&local_err); - - status = 1; } else { if (!opt_noprogress) { if (tool_is_stdout_tty()) From 1b694112fc44232c099880db8afb8fed4421214b Mon Sep 17 00:00:00 2001 From: aurelien Date: Thu, 15 Oct 2020 00:29:26 +0200 Subject: [PATCH 18/33] Add range selection to the downloader --- tools/dl.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/dl.c b/tools/dl.c index e25c759..b57d155 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -139,14 +139,28 @@ static gint* parse_number_list(const gchar* input, gint* count) return NULL; gchar** tokens = g_regex_split(re, input, 0); - guint i = 0, n_tokens = g_strv_length(tokens); + guint i = 0, j = 0, n_tokens = g_strv_length(tokens), n_nums = n_tokens; gint* nums = g_new0(gint, n_tokens); *count = 0; - while (i < n_tokens) { + while (i < n_tokens) { if (g_regex_match_simple("^\\d{1,7}$", tokens[i], 0, 0)) { nums[*count] = atoi(tokens[i]); *count += 1; + } else if (g_regex_match_simple("^\\d{1,7}-\\d{1,7}$", tokens[i], 0, 0)) { + gchar** tokens_range = g_regex_split_simple("-", tokens[i], 0, 0); + int min = atoi(tokens_range[0]), max = atoi(tokens_range[1]); + if (min < max) { + n_nums += max - min; + nums = g_renew(gint, nums, n_nums); + for (j = min; j <= max; ++j) { + nums[*count] = j; + *count += 1; + } + } else { + g_printerr("WARNING: Skipping empty range '%s'\n", tokens[i]); + } + g_strfreev(tokens_range); } else { g_printerr("WARNING: Skipping non-numeric value '%s'\n", tokens[i]); } @@ -162,7 +176,7 @@ static GSList *prompt_and_filter_nodes(GSList *nodes) { GSList *chosen_nodes = NULL; - gc_free gchar* input = tool_prompt_input(); + gc_free gchar* input = tool_prompt_input(); if (input == NULL) return g_slist_copy(nodes); @@ -278,7 +292,7 @@ static GSList* pick_nodes(void) position++; } - g_print("Enter numbers of files or folders to download separated by spaces (or type 'all' to download everything):\n> "); + g_print("Enter numbers of files or folders to download separated by spaces (or type 'all' to download everything, or a range with two numbers separated by '-'):\n> "); chosen_nodes = prompt_and_filter_nodes(nodes); From b938d7a3301e438a126d0a515b846e13b74381b6 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Thu, 15 Oct 2020 01:36:44 +0200 Subject: [PATCH 19/33] Cleanup the dl range code - free as soon as tokens_range is not needed - allow inverted ranges - allow ranges of 1-1 or 5-5 - fix off-by-1 in g_renew - sanity check for extremely large ranges --- tools/dl.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/dl.c b/tools/dl.c index b57d155..1534aec 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -150,17 +150,25 @@ static gint* parse_number_list(const gchar* input, gint* count) } else if (g_regex_match_simple("^\\d{1,7}-\\d{1,7}$", tokens[i], 0, 0)) { gchar** tokens_range = g_regex_split_simple("-", tokens[i], 0, 0); int min = atoi(tokens_range[0]), max = atoi(tokens_range[1]); - if (min < max) { - n_nums += max - min; + g_strfreev(tokens_range); + + if (min > max) { + int tmp = max; + max = min; + min = tmp; + } + + if ((max - min) > 5000) { + g_printerr("WARNING: Skipping suspiciously large range '%s'\n", tokens[i]); + } else { + n_nums += max - min + 1; nums = g_renew(gint, nums, n_nums); + for (j = min; j <= max; ++j) { nums[*count] = j; *count += 1; } - } else { - g_printerr("WARNING: Skipping empty range '%s'\n", tokens[i]); } - g_strfreev(tokens_range); } else { g_printerr("WARNING: Skipping non-numeric value '%s'\n", tokens[i]); } From e5c89d933544bd443c86d83934cb446b521618a8 Mon Sep 17 00:00:00 2001 From: ivesen Date: Sun, 8 Nov 2020 20:00:26 +0100 Subject: [PATCH 20/33] add support for newstyle folders --- tools/dl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/dl.c b/tools/dl.c index 1534aec..a93c657 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -367,6 +367,7 @@ static struct { { "^https?://mega\\.nz/file/([a-z0-9_-]{8})#([a-z0-9_-]{43})$", LINK_FILE }, { "^https?://mega(?:\\.co)?\\.nz/#F!([a-z0-9_-]{8})!([a-z0-9_-]{22})(?:[!?]([a-z0-9_-]{8}))?$", LINK_FOLDER }, { "^https?://mega\\.nz/folder/([a-z0-9_-]{8})#([a-z0-9_-]{22})/file/([a-z0-9_-]{8})$", LINK_FOLDER }, + { "^https?://mega\\.nz/folder/([a-z0-9_-]{8})#([a-z0-9_-]{22})/folder/([a-z0-9_-]{8})$", LINK_FOLDER }, { "^https?://mega\\.nz/folder/([a-z0-9_-]{8})#([a-z0-9_-]{22})$", LINK_FOLDER }, }; From 5cf28e2a30bb5f30d8c89226a5a0f081d96f0248 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Thu, 28 Oct 2021 10:28:58 +0200 Subject: [PATCH 21/33] Try disabling TLS session ID cache (may fix #462) --- lib/http.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/http.c b/lib/http.c index 033f1e8..1a33474 100644 --- a/lib/http.c +++ b/lib/http.c @@ -168,6 +168,8 @@ struct http *http_new(void) curl_easy_setopt(h->curl, CURLOPT_BUFFERSIZE, 256 * 1024L); + curl_easy_setopt(h->curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); + #if CURL_AT_LEAST_VERSION(7, 44, 0) const gchar* pkp_disable = g_getenv("MEGATOOLS_PKP_DISABLE"); if (pkp_disable == NULL || strcmp(pkp_disable, "1")) { From 9a6365c41d95d9a48387e9f8d51242b1f213e460 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Fri, 1 Apr 2022 19:32:51 +0200 Subject: [PATCH 22/33] Use g_memdup2 --- lib/mega.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/mega.c b/lib/mega.c index 3780ceb..85b0738 100644 --- a/lib/mega.c +++ b/lib/mega.c @@ -851,7 +851,7 @@ static guchar *make_random_key(void) //XXX: error check RAND_bytes(k, sizeof(k)); - return g_memdup(k, 16); + return g_memdup2(k, 16); } // }}} @@ -880,7 +880,7 @@ static guchar *make_password_key(const gchar *password) } } - return g_memdup(pkey, 16); + return g_memdup2(pkey, 16); } // }}} @@ -1824,7 +1824,7 @@ void add_share_key(struct mega_session *s, const gchar *handle, const guchar *ke g_return_if_fail(handle != NULL); g_return_if_fail(key != NULL); - g_hash_table_insert(s->share_keys, g_strdup(handle), g_memdup(key, 16)); + g_hash_table_insert(s->share_keys, g_strdup(handle), g_memdup2(key, 16)); } // }}} @@ -2381,7 +2381,7 @@ gboolean mega_session_open(struct mega_session *s, const gchar *un, const gchar sizeof(key), key); g_free(s->password_key); - s->password_key = g_memdup(key, 16); + s->password_key = g_memdup2(key, 16); uh = base64urlencode(key + 16, 16); } else { @@ -3073,7 +3073,7 @@ gchar *mega_session_new_node_attribute(struct mega_session *s, const guchar *dat // encrypt AES_set_encrypt_key(key, 128, &k); - gc_free guchar *plain = g_memdup(data, len); + gc_free guchar *plain = g_memdup2(data, len); plain = g_realloc(plain, len + pad); memset(plain + len, 0, pad); gc_free guchar *cipher = g_malloc0(len + pad); From 3faff7afd44b0058d8a276b8622d9b6d09209daf Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Wed, 18 May 2022 18:44:41 +0200 Subject: [PATCH 23/33] Improve support for UTF-8 on windows --- lib/mega.c | 7 ----- lib/tools.c | 76 ++++---------------------------------------------- lib/tools.h | 1 - meson.build | 2 +- tools/dl.c | 3 +- tools/export.c | 2 +- tools/get.c | 2 +- tools/ls.c | 2 +- tools/mkdir.c | 2 +- tools/put.c | 2 +- tools/rm.c | 2 +- tools/shell.c | 45 ++++++++++++++++++++++++++++++ tools/test.c | 2 +- 13 files changed, 59 insertions(+), 89 deletions(-) diff --git a/lib/mega.c b/lib/mega.c index 85b0738..cfea9f7 100644 --- a/lib/mega.c +++ b/lib/mega.c @@ -1621,15 +1621,8 @@ static void build_node_tree(struct mega_session *s) for (i = s->fs_nodes; i; i = i->next) { struct mega_node *n = i->data; -#if GLIB_CHECK_VERSION(2, 40, 0) if (!g_hash_table_insert(handle_map, n->handle, n)) g_printerr("WARNING: Dup node handle detected %s\n", n->handle); -#else - if (g_hash_table_lookup(handle_map, n->handle)) - g_printerr("WARNING: Dup node handle detected %s\n", n->handle); - else - g_hash_table_insert(handle_map, n->handle, n); -#endif } for (i = s->fs_nodes; i;) { diff --git a/lib/tools.c b/lib/tools.c index 37916cd..367376b 100644 --- a/lib/tools.c +++ b/lib/tools.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "config.h" #include "tools.h" @@ -165,7 +164,6 @@ static void init_openssl_locking() // OpenSSL >= 1.1.0-pre4 doesn't require specific callback setup } #else -#if GLIB_CHECK_VERSION(2, 32, 0) static GMutex *openssl_mutexes = NULL; @@ -198,55 +196,10 @@ static void init_openssl_locking() CRYPTO_set_locking_callback(openssl_locking_callback); } -#else - -static GMutex **openssl_mutexes = NULL; - -static void openssl_locking_callback(int mode, int type, const char *file, int line) -{ - if (mode & CRYPTO_LOCK) - g_mutex_lock(openssl_mutexes[type]); - else - g_mutex_unlock(openssl_mutexes[type]); -} - -static unsigned long openssl_thread_id_callback() -{ - unsigned long ret; - ret = (unsigned long)g_thread_self(); - return ret; -} - -static void init_openssl_locking() -{ - gint i; - - // initialize OpenSSL locking for multi-threaded operation - openssl_mutexes = g_new(GMutex *, CRYPTO_num_locks()); - for (i = 0; i < CRYPTO_num_locks(); i++) - openssl_mutexes[i] = g_mutex_new(); - - SSL_library_init(); - CRYPTO_set_id_callback(openssl_thread_id_callback); - CRYPTO_set_locking_callback(openssl_locking_callback); -} - -#endif #endif static void init(void) { -#if !GLIB_CHECK_VERSION(2, 32, 0) - if (!g_thread_supported()) - g_thread_init(NULL); -#endif - - setlocale(LC_ALL, ""); - -#if !GLIB_CHECK_VERSION(2, 36, 0) - g_type_init(); -#endif - g_setenv("GSETTINGS_BACKEND", "memory", TRUE); #ifndef G_OS_WIN32 @@ -438,37 +391,16 @@ static void print_version(void) { if (opt_version) { g_print("megatools " VERSION " - command line tools for Mega.nz\n\n"); - g_print("Written by Ondrej Jirman , 2013-2018\n"); + g_print("Written by Ondrej Jirman , 2013-2022\n"); g_print("Go to http://megatools.megous.com for more information\n"); exit(0); } } -gchar *tool_convert_filename(const gchar *path, gboolean local) -{ - gchar *locale_path; - -#ifdef G_OS_WIN32 - locale_path = g_locale_to_utf8(path, -1, NULL, NULL, NULL); -#else - if (local) - locale_path = g_strdup(path); - else - locale_path = g_locale_to_utf8(path, -1, NULL, NULL, NULL); -#endif - - if (locale_path == NULL) { - g_printerr( - "ERROR: Invalid filename locale, can't convert file names specified on the command line to UTF-8.\n"); - exit(1); - } - - return locale_path; -} - void tool_init(gint *ac, gchar ***av, const gchar *tool_name, GOptionEntry *tool_entries, ToolInitFlags flags) { GError *local_err = NULL; + gchar** args = NULL; init(); @@ -488,12 +420,14 @@ void tool_init(gint *ac, gchar ***av, const gchar *tool_name, GOptionEntry *tool g_option_context_add_main_entries(opt_context, network_options, NULL); g_option_context_add_main_entries(opt_context, basic_options, NULL); - if (!g_option_context_parse(opt_context, ac, av, &local_err)) { + if (!g_option_context_parse_strv(opt_context, av, &local_err)) { g_printerr("ERROR: Option parsing failed: %s\n", local_err->message); g_clear_error(&local_err); exit(1); } + *ac = g_strv_length(*av); + print_version(); if (!opt_no_config || opt_config) { diff --git a/lib/tools.h b/lib/tools.h index c26210c..e6b9f38 100644 --- a/lib/tools.h +++ b/lib/tools.h @@ -46,7 +46,6 @@ struct mega_session *tool_start_session(ToolSessionFlags flags); void tool_fini(struct mega_session *s); void tool_show_progress(const gchar *file, const struct mega_status_data *data); -gchar *tool_convert_filename(const gchar *path, gboolean local); gboolean tool_is_stdout_tty(void); gchar* tool_prompt_input(void); diff --git a/meson.build b/meson.build index 0501a23..1ddb9b5 100644 --- a/meson.build +++ b/meson.build @@ -11,7 +11,7 @@ add_global_arguments('-Wno-unused', '-Wno-pointer-sign', language: 'c') deps = [ dependency('threads'), - dependency('gio-2.0', version: '>=2.32.0'), + dependency('gio-2.0', version: '>=2.40.0'), dependency('libcurl'), dependency('openssl'), ] diff --git a/tools/dl.c b/tools/dl.c index a93c657..c806792 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -448,8 +448,7 @@ static int dl_main(int ac, char *av[]) // process links for (i = 1; i < ac; i++) { - gc_free gchar *link_utf8 = tool_convert_filename(av[i], FALSE); - gc_free gchar *link = g_uri_unescape_string(link_utf8, NULL); + gc_free gchar *link = g_uri_unescape_string(av[i], NULL); struct mega_link l; if (!parse_link(link, &l)) { diff --git a/tools/export.c b/tools/export.c index 0ec0cfc..0265e51 100644 --- a/tools/export.c +++ b/tools/export.c @@ -46,7 +46,7 @@ static int export_main(int ac, char *av[]) } for (gint j = 1; j < ac; j++) { - gc_free gchar *path = tool_convert_filename(av[j], FALSE); + gchar *path = av[j]; struct mega_node *n = mega_session_stat(s, path); if (!n) { diff --git a/tools/get.c b/tools/get.c index f6bd6f8..89294eb 100644 --- a/tools/get.c +++ b/tools/get.c @@ -99,7 +99,7 @@ static int get_main(int ac, char *av[]) } for (i = 1; i < ac; i++) { - gc_free gchar *path = tool_convert_filename(av[i], FALSE); + gchar *path = av[i]; // perform download if (!mega_session_get_compat(s, opt_path, path, &local_err)) { diff --git a/tools/ls.c b/tools/ls.c index 2713543..21a1591 100644 --- a/tools/ls.c +++ b/tools/ls.c @@ -82,7 +82,7 @@ static int ls_main(int ac, char *av[]) opt_names = FALSE; for (j = 1; j < ac; j++) { - gc_free gchar *path = tool_convert_filename(av[j], FALSE); + gchar *path = av[j]; struct mega_node *n = mega_session_stat(s, path); if (n && (n->type == MEGA_NODE_FILE || !opt_names)) diff --git a/tools/mkdir.c b/tools/mkdir.c index 9dcca5c..bc3da73 100644 --- a/tools/mkdir.c +++ b/tools/mkdir.c @@ -44,7 +44,7 @@ static int mkdir_main(int ac, char *av[]) gint i, status = 0; for (i = 1; i < ac; i++) { - gc_free gchar *path = tool_convert_filename(av[i], FALSE); + gchar *path = av[i]; if (!mega_session_mkdir(s, path, &local_err)) { g_printerr("ERROR: Can't create directory %s: %s\n", path, local_err->message); diff --git a/tools/put.c b/tools/put.c index 56d9679..2a8a434 100644 --- a/tools/put.c +++ b/tools/put.c @@ -61,7 +61,7 @@ static int put_main(int ac, char *av[]) gint status = 0; gint i; for (i = 1; i < ac; i++) { - gc_free gchar *path = tool_convert_filename(av[i], TRUE); + gchar *path = av[i]; g_free(cur_file); cur_file = g_path_get_basename(path); diff --git a/tools/rm.c b/tools/rm.c index 61031ec..e685c66 100644 --- a/tools/rm.c +++ b/tools/rm.c @@ -43,7 +43,7 @@ static int rm_main(int ac, char *av[]) gint i, status = 0; for (i = 1; i < ac; i++) { - gc_free gchar *path = tool_convert_filename(av[i], FALSE); + gchar *path = av[i]; if (!mega_session_rm(s, path, &local_err)) { g_printerr("ERROR: Can't remove %s: %s\n", path, local_err->message); diff --git a/tools/shell.c b/tools/shell.c index db07465..116be9f 100644 --- a/tools/shell.c +++ b/tools/shell.c @@ -21,6 +21,12 @@ #include "shell.h" #include "config.h" #include "lib/alloc.h" +#ifdef G_OS_WIN32 +#include +#include +#include +#endif +#include extern struct shell_tool shell_tool_df; extern struct shell_tool shell_tool_dl; @@ -48,8 +54,47 @@ static struct shell_tool* tools[] = { &shell_tool_reg, }; +#ifdef G_OS_WIN32 +static unsigned int initial_cp; + +static void print_no_convert(const gchar *buf) +{ + fputs(buf, stdout); + fflush(stdout); +} + +static void printerr_no_convert(const gchar *buf) +{ + fputs(buf, stderr); + fflush(stderr); +} + +static void restore_console(void) +{ + SetConsoleOutputCP(initial_cp); +} +#endif + int main(int ac, char *av[]) { +#ifdef G_OS_WIN32 + setlocale(LC_ALL, "C"); + + av = g_win32_get_command_line(); + ac = g_strv_length(av); + + g_set_print_handler(print_no_convert); + g_set_printerr_handler(printerr_no_convert); + + initial_cp = GetConsoleOutputCP(); + SetConsoleOutputCP(CP_UTF8); + atexit(restore_console); +#else + setlocale(LC_ALL, ""); + + av = g_strdupv(av); +#endif + gc_free gchar* cmd_basename = g_path_get_basename(av[0]); gchar* cmd_name = NULL; diff --git a/tools/test.c b/tools/test.c index 4b25953..cd06ba0 100644 --- a/tools/test.c +++ b/tools/test.c @@ -56,7 +56,7 @@ static int test_main(int ac, char *av[]) } for (gint j = 1; j < ac; j++) { - gc_free gchar *path = tool_convert_filename(av[j], FALSE); + gchar *path = av[j]; struct mega_node *n = mega_session_stat(s, path); if (!n) { From dc9e77fbc1db9c01895ca61b3a07d2046c2199de Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Thu, 19 May 2022 17:01:46 +0200 Subject: [PATCH 24/33] Update NEWS/README for release of 1.11.0 --- NEWS | 101 ++++++++++++++++++++++++++++++++++++++++++++++-- docs/footer.txt | 2 +- tools/shell.c | 2 +- 3 files changed, 100 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index d6f0107..3ec47dd 100644 --- a/NEWS +++ b/NEWS @@ -1,18 +1,113 @@ -megatools 1.10.3 - 2018-08-?? +megatools 1.11.0 - 2022-05-19 ============================= This release introduces new features. Improvements: + - Megatools now install a single `megatools` executable, where former `megaXYZ ...` commands now have to be executed as `megatools XYZ ...`. - Implemented PKP (public key pinning for mega.nz's API server). Megatools no longer use public certificate authorities to verify API server's authenticity. If you use software that MITM's your web traffic, megatools will not allow this anymore. +- Windows builds no longer need any special console setup to support UTF-8. + It just works out of the box. +- Support new public folder URLs in `dl` +- Build system moved to meson +- New `test` command for checking if file exists +- New `export` command for creating public links for private files +- Login v2 support +- Upload reliability improvements + +Commit list: + +9294db2 Improve support for UTF-8 on windows +82833a2 Use g_memdup2 +4adc57f Try disabling TLS session ID cache (may fix #462) +3f59e27 add support for newstyle folders +8b759a3 Cleanup the dl range code +e299c43 Add range selection to the downloader +539ff6f Return status = 2 if uploaded file already exists +c0bd7ef Add file exists error type +8d91a61 Fix NULL pointer dereference when invoking megatools in some situations +57cddce Bump cache format version +1737c55 Cleanup login v2 support and fix session caching +bf886a4 Add contributed support for v2 login flow +e4e8495 dl: Support new link format for individual files inside folders +fe6d818 dl: Add support for new link formats +8296db8 Update README with new build information/git repository link +471a3cf Make doc generator programs optional +9e47ad4 Move to meson buildystem +eae38e9 Drop github issue template +a9af5d8 Update PGP fingerprint +1f52c9c We need to follow symlinks on local paths in megatools dl +8bbc21c Mark some functions as static +32bd83a Change e-mail/website addresses +2d9fe44 URL-decode links passed to the dl command #310 +cc91968 Add --ip-proto and --netif options +f19cf39 Add export tool +d3e1d58 Add megatools test tool +f0bfefd Drop useless ; +7735dd2 Fix grammar: data are -> data is +99dfea8 Avoid new compiler warnings +2c7e2a3 No need to iterate from the beginning when checking for invalid filename +4e5ba97 Replace invalid filename characters with _ instead of a space +1aeb275 Merge branch 'master' of github.com:megous/megatools +956c11a Don't use alloca, avoid unbounded path construction +c94277f Merge pull request #428 from 64617/fix-filename +c91409c Don't immediately fail on invalid filename +2cc7019 Fixes: 'megatools get', Output to STDOUT not working #423 +1012d6e Updated todo +0faba1c Fix megatools rm not removing the child nodes from the fs_nodes +65f8afd Don't free nodes too early #417 +a1c945c dl: Download exported files even if root is not a folder #417 +2ca921f Merge branch 'master' into x +f651ba0 Revert "Support ....?.... URL scheme for single file downloads" +d52d0ce Refactor update_pathmap_prune to make it clearer, fix memleaks +7f2dcae Merge pull request #417 from mdirik/file-url +c78d0d6 Support ....?.... URL scheme for single file downloads +8758b65 Sort order of downloads #401 +8309767 Merge pull request #414 from taiyu-len/master +978e4be Show file sizes in pick_nodes +28a2fbe Drop libmega mentions #412 +1ea525e Fix download speed limit not being applied by curl if handle is re-used #380 +2b68a46 Fix implicitly declared function warnings in shell.c #406 +3c24b71 Add link for the experimental windows builds +f218192 Optimize exported folder filesystem parsing #405 +0e21e38 Fix megac doc +b04961d Fix parameter type to curl_easy_setopt +ac07641 Fix for "Hardcoded colors affects readability" #404 +2255c5d Allow more retries during download (when over quota) #403 +0346e76 Add git warning/build instructions to autogen.sh +548042e Add gc_tool_fini attribute +653ba6c Fix alignment of exported links +26a7a0d Add docbook-xml dependency #391 +3459d1f Update issue template +1a7e3f4 Update README file for 1.11.0 +70c624e Don't download data when file already exists when using megadl #386 +5acf268 Add -std=c99 compiler flag +a6df742 Always retry the upload, on any server returned error +80e9767 Drop special handling of EAGAIN +7827235 Report possibly transient failures from curl as HTTP_ERROR_COMM_FAILURE +9c150b3 Bump version to 1.11.0-git +3637555 Drop AC_PROG_RANLIB (libtool is enough) +f6dcdf5 Don't be too silent +095d284 Fix contact information +d2c5c38 Improve build instructions #384 +b304d5c Use libtool to fix static linking +d7b9037 Drop option groups +a4f638e Fix a couple of typos +b95ac5d Updated NEWS/TODO +63771cd Drop dead autoconf code +4437c0c Update megatools docs for the new command naming scheme +852852b Add option to install compat links +6cbd650 Build a single binary instead of a binary for each command +6736622 Drop accent +7ac9569 Bump the year +ff0f5f1 We don't use gnutls/glib-networking anymore, drop unnecessary code +07ba1f9 Implement public key pinning for the API server -Fixes: -- megatools 1.10.2 - 2018-07-31 ============================= diff --git a/docs/footer.txt b/docs/footer.txt index 7f1f7ca..4dca92e 100644 --- a/docs/footer.txt +++ b/docs/footer.txt @@ -28,6 +28,6 @@ archive, so be careful what you say or send. AUTHOR ------ -Megatools was written by Ondrej Jirman , 2013-2019. +Megatools was written by Ondrej Jirman , 2013-2022. Official website is link:http://megatools.megous.com[]. diff --git a/tools/shell.c b/tools/shell.c index 116be9f..9ec935a 100644 --- a/tools/shell.c +++ b/tools/shell.c @@ -135,7 +135,7 @@ int main(int ac, char *av[]) g_print("\n"); g_print("megatools " VERSION " - command line tools for Mega.nz\n"); - g_print("Written by Ondrej Jirman , 2013-2018\n"); + g_print("Written by Ondrej Jirman , 2013-2022\n"); g_print("Go to http://megatools.megous.com for more information\n"); return 1; } From efa3810947789b2da471c504db0faea6c9a4ea13 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 23 May 2022 22:19:56 +0200 Subject: [PATCH 25/33] Fix typo --- docs/download-options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/download-options.txt b/docs/download-options.txt index e2824b3..082e5fc 100644 --- a/docs/download-options.txt +++ b/docs/download-options.txt @@ -1,3 +1,3 @@ --disable-resume:: - Don't resume downloads from partially dowloaded file. Default is to + Don't resume downloads from partially downloaded file. Default is to resume. From 67913406567f88561448a6b1c87c4067364a61f8 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 19 Sep 2022 17:21:26 +0200 Subject: [PATCH 26/33] dl: Fix file links when base64 contains trailing = --- tools/dl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/dl.c b/tools/dl.c index c806792..b088b1e 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -363,8 +363,8 @@ static struct { int type; GRegex* re; } link_regexes[] = { - { "^https?://mega(?:\\.co)?\\.nz/#!([a-z0-9_-]{8})!([a-z0-9_-]{43})$", LINK_FILE }, - { "^https?://mega\\.nz/file/([a-z0-9_-]{8})#([a-z0-9_-]{43})$", LINK_FILE }, + { "^https?://mega(?:\\.co)?\\.nz/#!([a-z0-9_-]{8})!([a-z0-9_=-]{43}={0,2})$", LINK_FILE }, + { "^https?://mega\\.nz/file/([a-z0-9_-]{8})#([a-z0-9_-]{43}={0,2})$", LINK_FILE }, { "^https?://mega(?:\\.co)?\\.nz/#F!([a-z0-9_-]{8})!([a-z0-9_-]{22})(?:[!?]([a-z0-9_-]{8}))?$", LINK_FOLDER }, { "^https?://mega\\.nz/folder/([a-z0-9_-]{8})#([a-z0-9_-]{22})/file/([a-z0-9_-]{8})$", LINK_FOLDER }, { "^https?://mega\\.nz/folder/([a-z0-9_-]{8})#([a-z0-9_-]{22})/folder/([a-z0-9_-]{8})$", LINK_FOLDER }, From 78ba880cf502e7414a6b844e4c0937312d0d1d01 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 3 Oct 2022 12:50:57 +0200 Subject: [PATCH 27/33] Add info about manpage build on Ubuntu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested by Tomáš Hnyk From 2fa312671dbd8d9631a9b800604b9040eb8f45c6 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 21 Nov 2022 11:51:16 +0100 Subject: [PATCH 28/33] Fix installation instructions for 1.11.0 From efc221b200ece18ddc12255bc8a41abb8ded3581 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sun, 12 Feb 2023 19:16:22 +0100 Subject: [PATCH 29/33] Fix node not found error when downloading folders --- tools/dl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/dl.c b/tools/dl.c index b088b1e..05192f2 100644 --- a/tools/dl.c +++ b/tools/dl.c @@ -387,6 +387,8 @@ static gboolean parse_link(const char* url, struct mega_link* l) l->handle = g_match_info_fetch(m, 1); l->key = g_match_info_fetch(m, 2); l->specific = g_match_info_fetch(m, 3); + if (l->specific && !l->specific[0]) + g_clear_pointer(&l->specific, g_free); g_clear_pointer(&m, g_match_info_unref); return TRUE; From 5c7e5ae09bc4216a39f3656fa1dabe0bbe052446 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sun, 12 Feb 2023 19:31:49 +0100 Subject: [PATCH 30/33] Avoid curl deprecations --- lib/http.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/http.c b/lib/http.c index 1a33474..5b60c83 100644 --- a/lib/http.c +++ b/lib/http.c @@ -160,7 +160,7 @@ struct http *http_new(void) curl_easy_setopt(h->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(h->curl, CURLOPT_NOSIGNAL, 1L); - curl_easy_setopt(h->curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); + curl_easy_setopt(h->curl, CURLOPT_PROTOCOLS_STR, "http,https"); curl_easy_setopt(h->curl, CURLOPT_TCP_KEEPALIVE, 1L); curl_easy_setopt(h->curl, CURLOPT_TCP_KEEPIDLE, 120L); @@ -243,7 +243,7 @@ void http_set_content_length(struct http *h, goffset len) g_free(tmp); } -static int curl_progress(struct http *h, double dltotal, double dlnow, double ultotal, double ulnow) +static int curl_progress(struct http *h, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { if (h->progress_cb) { if (!h->progress_cb(dltotal, dlnow, ultotal, ulnow, h->progress_data)) @@ -273,7 +273,7 @@ void http_set_progress_callback(struct http *h, http_progress_fn cb, gpointer da h->progress_data = data; curl_easy_setopt(h->curl, CURLOPT_NOPROGRESS, 0L); - curl_easy_setopt(h->curl, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)curl_progress); + curl_easy_setopt(h->curl, CURLOPT_XFERINFOFUNCTION, curl_progress); curl_easy_setopt(h->curl, CURLOPT_PROGRESSDATA, h); } else { curl_easy_setopt(h->curl, CURLOPT_NOPROGRESS, 1L); From d52d29da2e91f4d3e129b660aee5d3afaccace13 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sun, 12 Feb 2023 19:32:14 +0100 Subject: [PATCH 31/33] Avoid gcc warning for strncpy --- lib/mega.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mega.c b/lib/mega.c index cfea9f7..f508f93 100644 --- a/lib/mega.c +++ b/lib/mega.c @@ -873,7 +873,7 @@ static guchar *make_password_key(const gchar *password) AES_KEY k; guchar key[16] = { 0 }, pkey_tmp[16]; - strncpy(key, password + i, 16); // this is fine, we don't need a NUL termination here, stfu gcc8! + memcpy(key, password + i, MIN(16, len - i)); AES_set_encrypt_key(key, 128, &k); AES_encrypt(pkey, pkey_tmp, &k); memcpy(pkey, pkey_tmp, 16); From f01d0ea925a3d7b4858646a772e458a605f51199 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sun, 12 Feb 2023 20:39:35 +0100 Subject: [PATCH 32/33] Prepare for 1.11.1 release --- NEWS | 10 ++++++++++ meson.build | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 3ec47dd..d3998fa 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,13 @@ +megatools 1.11.1 - 2023-02-12 +============================= + +This is just a bugfix release. + +Fixes: + +- fix folder downloads +- fix handling of = in mega URLs + megatools 1.11.0 - 2022-05-19 ============================= diff --git a/meson.build b/meson.build index 1ddb9b5..2649269 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('megatools', 'c', - version: '1.11.0', + version: '1.11.1', default_options: [ 'c_std=gnu99', ], From 5e8d71b8b3feef42066c58eadcaf2605282e2f62 Mon Sep 17 00:00:00 2001 From: "Theodore R. Smith" Date: Fri, 9 Aug 2024 12:11:04 -0500 Subject: [PATCH 33/33] Added the ninja build system. --- .gitignore | 5 +++ Makefile.am | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ README | 45 ++++++++++++++++++++++ autogen.sh | 25 +++++++++++++ build.ninja | 95 +++++++++++++++++++++++++++++++++++++++++++++++ build.sh | 71 +++++++++++++++++++++++++++++++++++ configure.ac | 71 +++++++++++++++++++++++++++++++++++ docs/Makefile | 35 +++++++++++++++++ 8 files changed, 448 insertions(+) create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 build.ninja create mode 100755 build.sh create mode 100644 configure.ac create mode 100644 docs/Makefile diff --git a/.gitignore b/.gitignore index 31ced45..ee28596 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,8 @@ /docs/*.1 /docs/*.5 + +.ninja_log +.idea/ +libtool +ltmain.sh diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..c2c7bf7 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,101 @@ +# global flags + +SUBDIRS = docs + +COMMANDS = df dl get ls test export mkdir put reg rm copy + +ACLOCAL_AMFLAGS = -I m4 + +AM_CFLAGS = \ + $(GLIB_CFLAGS) \ + $(OPENSSL_CFLAGS) \ + $(LIBCURL_CFLAGS) \ + -DG_LOG_DOMAIN=\"Mega\" \ + -I$(srcdir)/lib \ + -I$(srcdir) \ + -std=c99 + +LDADD = \ + $(GLIB_LIBS) \ + $(OPENSSL_LIBS) \ + $(LIBCURL_LIBS) + +# tools + +EXTRA_DIST = lib/sjson.c + +bin_PROGRAMS = megatools +megatools_SOURCES = \ + lib/sjson.gen.c \ + lib/sjson.h \ + lib/http.c \ + lib/http.h \ + lib/mega.c \ + lib/mega.h \ + lib/tools.c \ + lib/tools.h \ + lib/alloc.h \ + lib/mega.h \ + tools/df.c \ + tools/dl.c \ + tools/get.c \ + tools/ls.c \ + tools/test.c \ + tools/export.c \ + tools/mkdir.c \ + tools/put.c \ + tools/reg.c \ + tools/rm.c \ + tools/copy.c \ + tools/shell.c \ + tools/shell.h + +# Use an object directory +AUTOMAKE_OPTIONS = subdir-objects + +if INSTALL_COMPAT_SYMLINKS + +install-exec-hook: + cd $(DESTDIR)$(bindir) && \ + for cmd in $(COMMANDS) ; do \ + rm -f mega$$cmd$(EXEEXT) ; \ + $(LN_S) megatools$(EXEEXT) mega$$cmd$(EXEEXT) ; \ + done + +endif + +# Cleanup rule to remove .o files +clean-objects: + @echo "Cleaning up object files..." + rm -f ./lib/*.o ./tools/*.o + +# Hook the cleanup rule after the installation +install: all install-exec clean-objects + +# docs + +MAN1 = megatools $(addprefix megatools-,$(COMMANDS)) +MAN5 = megarc + +man1_MANS = $(addprefix docs/,$(addsuffix .1, $(MAN1))) +man5_MANS = $(addprefix docs/,$(addsuffix .5, $(MAN5))) + +EXTRA_DIST += $(man1_MANS) $(man5_MANS) + +EXTRA_DIST += LICENSE HACKING contrib/bash-completion/megatools + +doc_DATA = LICENSE NEWS TODO README INSTALL HACKING + +EXTRA_DIST += \ + docs/auth-options.txt \ + docs/basic-options.txt \ + docs/download-options.txt \ + docs/footer.txt \ + docs/megarc.txt \ + $(addsuffix .txt,$(addprefix docs/megatools-,$(COMMANDS))) \ + docs/megatools.txt \ + docs/network-options.txt \ + docs/remote-paths.txt \ + docs/upload-options.txt \ + docs/asciidoc.conf \ + docs/Makefile diff --git a/README b/README index 2979c99..4d95888 100644 --- a/README +++ b/README @@ -20,6 +20,51 @@ password. Mega website can be found at https://mega.nz. +How To Build +============= +Run + + ./build.sh + +The first time, it will build either using [**ninja**](https://ninja-build.org/) (if available) +or GNU Make if it is not. + +After the initial time, it will stay active, waiting for changes to the *.c files, +and will compile automatically. + +################## NOTICE ########################### # This has been forked and is actively maintained: https://github.com/BitBasket/megatools +################## NOTICE ########################### + +Contributors +============ + +- Alberto Garcia +- aurelien +- bAndie91 +- Chris Tarazi +- cyrozap +- Dal1a +- David Guillen Fandos +- Erik Nordstrøm +- ivesen +- Johnathan Jenkins +- Kagami Hiiragi +- Matthew Schultz +- Max Base +- Mert Dirik +- Michael Ledin +- Michael Ripley +- nyuszika7h +- Palmer Dabbelt +- protomouse +- RealDolos +- strupo +- taiyu +- Theodore R. Smith +- Tom Maneiro +- Viktor (Icon) VAD +- wdlkmpx + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..7dd11e5 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,25 @@ +#! /bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir + +mkdir -p m4 + +autoreconf -v --install || exit 1 +cd $ORIGDIR || exit $? + +$srcdir/configure --enable-maintainer-mode --enable-warnings "$@" + +cat << EOF +========================================================================= +| WARNING You're building from GIT code | +========================================================================= +| - Don't! git is for developers, release tarballs are for end users. | +| Get them here: https://megatools.megous.com/builds/ | +| - Read the README for build instructions! | +| - Random checkouts from git are not tested. | +========================================================================= +EOF \ No newline at end of file diff --git a/build.ninja b/build.ninja new file mode 100644 index 0000000..9d25381 --- /dev/null +++ b/build.ninja @@ -0,0 +1,95 @@ +# Variables +cc = gcc +#cc = $cc(gcc) +cflags = -g -O2 -Wall -I./lib -I. `pkg-config --cflags glib-2.0 gobject-2.0 gio-2.0` +ldflags = -lm `pkg-config --libs glib-2.0 gobject-2.0 gio-2.0 libcurl openssl` +default_prefix = /usr/local + +# Rules +rule cc + command = $cc $cflags -c $in -o $out + description = CC $out + +rule link + command = $cc $ldflags $in -o $out + description = LINK $out + +rule build-docs + command = make -C docs + description = Building documentation + pool = console + +# Clean rules +rule clean-objects + command = rm -f .obj/lib/*.o .obj/tools/*.o lib/*.o tools/*.o + description = Cleaning object files + +rule clean-docs + command = rm -f docs/*.1 + description = Cleaning documentation + +rule clean + command = rm -f .obj/lib/*.o .obj/tools/*.o megatools + description = Cleaning object files and executables + +rule clean-dist + command = ninja clean && ninja clean-docs && rm -f *.lo *.tab.c Makefile config.h stamp-h1 libtool config.lt config.status config.cache config.log configure.lineno config.status.lineno rm -rf ./autom4te.cache || true + description = Cleaning files created by ./configure and the build process + pool = console + +rule clean-pristine + command = ninja distclean && rm -rf m4 && rm -f Makefile.in aclocal.m4 compile config.guess config.h.in* config.sub configure configure.in depcomp install-sh ltmain.sh || true + description = Cleaning everything not in the git repo + pool = console + +rule build-autogen + command = ./autogen.sh + pool = console + +build config.h.in: build-autogen +#build configure.ac: phony + +rule build-configure + command = ./configure --prefix=$PREFIX + description = Configuring with prefix $PREFIX + pool = console + +build config.h: build-configure | config.h.in + PREFIX = $default_prefix +#build config.h: phony + + +# Build targets +build .obj/lib/http.o: cc lib/http.c | config.h +build .obj/lib/mega.o: cc lib/mega.c | config.h +build .obj/lib/sjson.o: cc lib/sjson.c | config.h +build .obj/lib/sjson.gen.o: cc lib/sjson.gen.c | config.h +build .obj/lib/tools.o: cc lib/tools.c | config.h +build .obj/tools/copy.o: cc tools/copy.c | config.h +build .obj/tools/df.o: cc tools/df.c | config.h +build .obj/tools/dl.o: cc tools/dl.c | config.h +build .obj/tools/export.o: cc tools/export.c | config.h +build .obj/tools/get.o: cc tools/get.c | config.h +build .obj/tools/ls.o: cc tools/ls.c | config.h +build .obj/tools/mkdir.o: cc tools/mkdir.c | config.h +build .obj/tools/put.o: cc tools/put.c | config.h +build .obj/tools/reg.o: cc tools/reg.c | config.h +build .obj/tools/rm.o: cc tools/rm.c | config.h +build .obj/tools/shell.o: cc tools/shell.c | config.h +build .obj/tools/test.o: cc tools/test.c | config.h + +#build docs/megatools-dl.1: build-docs +build megatools: link .obj/lib/http.o .obj/lib/mega.o .obj/lib/sjson.gen.o .obj/lib/tools.o .obj/tools/copy.o .obj/tools/df.o .obj/tools/dl.o .obj/tools/export.o .obj/tools/get.o .obj/tools/ls.o .obj/tools/mkdir.o .obj/tools/put.o .obj/tools/reg.o .obj/tools/rm.o .obj/tools/shell.o .obj/tools/test.o | config.h + +build all: build-docs megatools | config.h + +build clean: clean + +build clean-docs: clean-docs + +build distclean: clean-dist + +build pristine: clean-pristine + +# Default target +default all diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..ea82a27 --- /dev/null +++ b/build.sh @@ -0,0 +1,71 @@ +#!/bin/sh + + + +# Check if inotifywait is installed +#if [ -z "$(which inotifywait)" ]; then +if ! command -v inotifywait ^> /dev/null; then + echo "inotifywait is not installed." + echo "Install the inotify-tools package and try again." + exit 1 +fi + +FIRST_BUILD=0 +if [ ! -f configure ]; then + FIRST_BUILD=1 +fi + +BUILD_SYSTEM=ninja +if ! command -v ninja ^> /dev/null; then + echo "WARNING: The ninja build system is not installed." + echo " Consider installing it for a much better experience." + echo + + BUILD_SYSTEM=make +fi + +function buildViaMake() { + if [ ! -f ./Makefile.in ]; then + ./autogen.sh + fi + + rm -f megatools + + make -j4 + + echo "All builds completed!" +} + +function build() { + if [ "${BUILD_SYSTEM}" = "make" ]; then + buildViaMake + else + ninja + fi +} + +build + +if [ $FIRST_BUILD -eq 1 ]; then + exit +fi + +# If Makefile.am is changed, rebuild the Makefiles... +(inotifywait -e close_write -m ./Makefile.am | while read; do + echo "Changed Makefile.am.." + ./autogen.sh + buildViaMake +done) & +WATCH1_PID=$! + + +## Watch for changes to .cs files in the directory and subdirectories +inotifywait --recursive --monitor --format "%e %w%f" \ + --event close_write,build.ninja $dir \ + --include '\.c$' | + while read changed; do + echo "Detected change in $changed" + build + done + +wait $WATCH1_PID \ No newline at end of file diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..cb51714 --- /dev/null +++ b/configure.ac @@ -0,0 +1,71 @@ +AC_PREREQ(2.60) +AC_INIT([megatools],[1.11.0-git],[megous@megous.com],[megatools]) +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADER([config.h]) +AM_INIT_AUTOMAKE([silent-rules foreign subdir-objects -Wno-portability]) +AM_MAINTAINER_MODE +AM_SILENT_RULES([yes]) + +AC_PROG_CC +#AC_PROG_RANLIB +AM_PROG_CC_C_O +AC_PROG_LN_S +AC_HEADER_STDC + +AC_LIBTOOL_WIN32_DLL +AM_PROG_LIBTOOL + +# Define requirements + +GLIB_VERSION="2.32.0" +LIBCURL_REQUIRES="libcurl" +OPENSSL_REQUIRES="openssl" + +# check for glib/gio +PKG_CHECK_MODULES(GLIB, [gio-2.0 >= $GLIB_VERSION]) +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) + +# check openssl +PKG_CHECK_MODULES(OPENSSL, [$OPENSSL_REQUIRES]) +AC_SUBST(OPENSSL_CFLAGS) +AC_SUBST(OPENSSL_LIBS) + +# check libcurl +PKG_CHECK_MODULES(LIBCURL, [$LIBCURL_REQUIRES]) +AC_SUBST(LIBCURL_CFLAGS) +AC_SUBST(LIBCURL_LIBS) + +# enable compatibility symlinks +AC_ARG_ENABLE([compat-symlinks], AC_HELP_STRING([--enable-compat-symlinks], [Install symlinks for compatibility with old megatools commands (megals, megacopy, megadl, ...).])) +AM_CONDITIONAL([INSTALL_COMPAT_SYMLINKS], [test "x$enable_compat_symlinks" = "xyes"]) + +# enable dev compiler warnings +AC_ARG_ENABLE([warnings], AC_HELP_STRING([--enable-warnings], [Build with compiler warnings enabled.])) +AS_IF([test "x$enable_warnings" = "xyes"], [ + CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-unused-local-typedefs -Wno-sign-compare -Wno-pointer-sign -Wno-missing-field-initializers" + + AS_IF([$CC --version | head -n1 | grep '(GCC) 4\.8' &>/dev/null], [CFLAGS="$CFLAGS -Wno-unused-local-typedefs"]) +], [ + CFLAGS="$CFLAGS -Wno-pointer-sign -Wno-unused-variable" + enable_warnings=no +]) + +AC_CONFIG_FILES([ + Makefile +]) + +AC_OUTPUT + +cat << EOF + +Configured features: + + warnings: $enable_warnings + +Run make now. + +NOTE: On FreeBSD, you need to use GNU make (gmake) + +EOF diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..8a7626d --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,35 @@ +# build docs + +VERSION = 1.10.3 +COMMANDS = df dl get ls test export mkdir put reg rm copy + +COMMON_DEPS = \ + asciidoc.conf \ + footer.txt \ + $(wildcard *-options.txt) \ + remote-paths.txt + +all: + +define MAN_template = +$(1).$(2): $(1).txt $(COMMON_DEPS) + a2x --asciidoc-opts="-f asciidoc.conf -o $$@" --destination-dir . -f manpage $$< + test $$(subst -,_,$$@) = $$@ || mv -f $$(subst -,_,$$@) $$@ + @sed -i 's/megatools_/megatools-/' $$@ + @sed -i 's/\[FIXME: manual]/Megatools Manual/' $$@ + @sed -i 's/\[FIXME: source]/megatools $(VERSION)/' $$@ + +all: $(1).$(2) +clean-$(1).$(2): + rm $(1).$(2) +clean: clean-$(1).$(2) +endef + +$(foreach cmd,$(COMMANDS),$(eval $(call MAN_template,megatools-$(cmd),1))) +$(eval $(call MAN_template,megatools,1)) +$(eval $(call MAN_template,megarc,5)) + +maintainer-clean: +distclean: +install-exec: +install: \ No newline at end of file