├── Makefile ├── README.md ├── configmanager.c ├── configmanager.h ├── download_kindle_lib.sh ├── entries_common.c ├── entries_common.h ├── http_request.c ├── http_request.h ├── json_common.c ├── json_common.h ├── json_entries_parse.c ├── json_entries_parse.h ├── json_oauth_parse.c ├── json_oauth_parse.h ├── lib ├── curlkindle │ ├── bin │ │ ├── curl │ │ └── curl-config │ ├── include │ │ └── curl │ │ │ ├── curl.h │ │ │ ├── curlbuild.h │ │ │ ├── curlrules.h │ │ │ ├── curlver.h │ │ │ ├── easy.h │ │ │ ├── mprintf.h │ │ │ ├── multi.h │ │ │ ├── stdcheaders.h │ │ │ ├── typecheck-gcc.h │ │ │ └── types.h │ └── lib │ │ └── pkgconfig │ │ └── libcurl.pc └── jsmn │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── example │ ├── jsondump.c │ └── simple.c │ ├── jsmn.c │ ├── jsmn.h │ ├── library.json │ ├── simple_example │ └── test │ ├── test.h │ ├── tests.c │ └── testutil.h ├── oauth_manager.c ├── oauth_manager.h ├── perform_entries.c ├── perform_entries.h ├── shared.c ├── shared.h ├── test ├── Makefile ├── _conffile.c ├── _entriescommon.c ├── _httprequest.c ├── _jsonauth.c ├── _jsonentries.c ├── _performentries.c ├── _wbac_compare.c ├── _wbac_init.c ├── _wbac_setstring.c ├── _wboa_init.c ├── alltests.c ├── files │ └── wallindle.json ├── greatest.h └── wallindle.cfg └── wallindle.c /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-O0 -g -m64 -std=iso9899:1999 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \ 3 | -Wno-missing-braces -Wextra -Wno-missing-field-initializers -Wformat=2 \ 4 | -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith \ 5 | -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline \ 6 | -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code \ 7 | -Wlogical-op -Wfloat-equal -Wstrict-aliasing=2 -Wredundant-decls \ 8 | -Wold-style-definition 9 | #-Werror 10 | 11 | ARM_CFLAGS=-mfpu=vfp -mfloat-abi=softfp -mtune=cortex-a8 -march=armv7-a 12 | 13 | LDFLAGS=lib/curl_x86_64/lib/libcurl.a -DCURL_STATICLIB -Ilib/curl_x86_64/include -lm 14 | LDFLAGS=`/usr/bin/curl-config --libs` -lm 15 | 16 | EXEC=wallindle 17 | 18 | OTHERC=configmanager.c entries_common.c http_request.c \ 19 | json_common.c json_entries_parse.c json_oauth_parse.c \ 20 | perform_entries.c shared.c \ 21 | lib/jsmn/jsmn.c 22 | 23 | all: clean build exec 24 | 25 | build: 26 | $(CC) $(CFLAGS) $(EXEC).c $(OTHERC) -o $(EXEC) $(LDFLAGS) 27 | 28 | exec: 29 | ./$(EXEC) 30 | 31 | clean: 32 | rm -rf $(EXEC) 33 | 34 | clear: clean 35 | 36 | mrproper: clean 37 | rm -rf $(EXEC) 38 | 39 | astyle: 40 | astyle --mode=c --style=attach --align-pointer=type --align-reference=name --add-braces \ 41 | --add-one-line-braces --attach-classes --attach-closing-while --max-code-length=80 \ 42 | --indent=spaces --break-blocks --suffix=none --lineend=linux \ 43 | --pad-header --pad-oper --pad-comma --indent=spaces=4 --indent-col1-comments \ 44 | *.c *.h 45 | 46 | arm: 47 | test -s lib/curlkindle/lib/libcrypto.so || { echo "libcurl.so not found. Run download_kindle_lib.sh (see README.md)."; exit 1; } 48 | # $(eval CC := arm-linux-gnueabi-gcc) 49 | $(eval CC := arm-kindle-linux-gnueabi-gcc) 50 | $(eval CFLAGS := -O0 -std=iso9899:1999 ) 51 | $(eval LDFLAGS := `./lib/curlkindle/bin/curl-config --libs` -lm) 52 | $(CC) $(CFLAGS) $(ARM_CFLAGS) wallindle.c $(OTHERC) -o $(EXEC) $(LDFLAGS) 53 | 54 | codewarnings: 55 | # clang-tidy wallindle.c -header-filter=.* -checks=*,clang-analyzer-*,-clang-analyzer-cplusplus* -- -std=iso9899:1999 56 | # clang-tidy wallindle.c $(OTHERC) -header-filter=.* -checks=*,-clang-analyzer-alpha.unix.Stream,-clang-analyzer-cplusplus*,llvm-header-guard,llvm-include-order -- -std=iso9899:1999 -lm 57 | clang-tidy wallindle.c $(OTHERC) -header-filter=.* -checks=*,-*,llvm-include-order -- -std=iso9899:1999 -lm 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What is Wallindle 2 | Wallindle is a native wallabag client for e-ink kindle. 3 | Wallindle fetch new articles in your Wallabag and add them to your 4 | kindle's unread ebooks. 5 | 6 | The standard way to "read-later" an article on the kindle is using a 7 | "read-later" online service and transmit the saved article to the kindle using 8 | Amazon "by-email" transmission. 9 | It works very well and with a very easy minimal setup ! 10 | 11 | However it relies on a two services which can be shut down at any moment. 12 | Wallabag can be your very own "read-later" service and in this case, Wallindle 13 | allows your e-ink kindle fetching saved articles autonomously ! 14 | 15 | # What do I need ? 16 | - An e-ink Kindle, 17 | [jailbroken](https://www.mobileread.com/forums/showthread.php?t=275881). 18 | If you don't undestand instructions, please do not attempt a jailbreak. 19 | 20 | - A Wallabag account (either your own instance or 21 | [a official one](https://www.wallabag.it/)) with some recent articles ! 22 | 23 | # Remerciements : 24 | 25 | - Kindle jailbreak scene 26 | - Gentoo Project for kindle toolchain 27 | - Wallabag team 28 | - Jsmn library for parsing jason in C 29 | - libcurl team 30 | - [Hervé](https://twitter.com/hervethouzard) for Wallabag support 31 | 32 | # Running Wallindle 33 | ## Building binary 34 | 35 | - You need a "arm-linux-gnueabi" compiler. You can easily find one in your 36 | linux distro repository. 37 | 38 | If you are a "Gentoo Linux" user I strongly recommend you builduing your own 39 | toolchain with crossdev : 40 | ```sh 41 | $ crossdev --stable -v -t arm-linux-gnueabi 42 | ``` 43 | - Get Wallindle sources : 44 | ``` 45 | git clone https://github.com/cekage/wallindle.git 46 | ``` 47 | - Download libcurl, libssl, libcrypt and libcrypto from the kindle using download_kindle_lib.sh : 48 | ``` 49 | $ cat download_kindle_lib.sh 50 | #!/usr/bin/env bash 51 | 52 | DEST=lib/curlkindle/lib 53 | SRC=/usr/lib 54 | KINDLEIP=192.168.15.244 55 | 56 | for lib in ssl curl crypt 57 | do 58 | scp root@${KINDLEIP}:${SRC}/lib${lib}*so ${DEST} 59 | done; 60 | 61 | $ ./download_kindle_lib.sh 62 | 63 | 64 | Welcome to Kindle! 65 | 66 | root@192.168.15.244's password: 67 | libssl.so 100% 287KB 6.0MB/s 286.7KB/s 00:00 68 | 69 | 70 | Welcome to Kindle! 71 | 72 | root@192.168.15.244's password: 73 | libcurl.so 100% 208KB 5.9MB/s 207.9KB/s 00:00 74 | 75 | 76 | Welcome to Kindle! 77 | 78 | root@192.168.15.244's password: 79 | libcrypt.so 100% 38KB 4.6MB/s 37.5KB/s 00:00 80 | libcrypto.so 100% 1393KB 6.2MB/s 1.4MB/s 00:00 81 | 82 | $ ls -alh lib/curlkindle/lib/*.so 83 | -rwxr-xr-x 1 k users 1,4M 3 sept. 20:53 lib/curlkindle/lib/libcrypto.so 84 | -rw-r--r-- 1 k users 38K 3 sept. 20:53 lib/curlkindle/lib/libcrypt.so 85 | -rwxr-xr-x 1 k users 208K 3 sept. 20:53 lib/curlkindle/lib/libcurl.so 86 | -rwxr-xr-x 1 k users 287K 3 sept. 20:53 lib/curlkindle/lib/libssl.so 87 | 88 | ``` 89 | - Adjust binaries path and name in Makefile 90 | - Make kindle native binary : 91 | ```sh 92 | $ make arm 93 | arm-linux-gnueabi-gcc -O0 -std=iso9899:1999 -mfpu=vfp -mfloat-abi=softfp -mtune=cortex-a8 -march=armv7-a wallindle.c configmanager.c entries_common.c entries_parse.c http_request.c json_common.c json_entries_parse.c json_oauth_parse.c oauth_manager.c perform_entries.c shared.c lib/jsmn/jsmn.c -o wallindle lib/curl_arm_32/lib/libcurl.a -lrt -DCURL_STATICLIB -Ilib/curl_arm_32/include -lm 94 | 95 | $ ls -alh wallindle 96 | -rwxr-xr-x 1 k users 193K 19 août 16:03 wallindle 97 | 98 | $ file wallindle 99 | wallindle: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.32, not stripped, with debug_info 100 | ``` 101 | ## Gathering informations 102 | - Get your very own oAuth2 credentials [follow instructions here](https://doc.wallabag.org/en/developer/api/oauth.html) 103 | 104 | - Prepare configuration : 105 | Basically, concatening (as a single line) host, client\_id, client\_secret, 106 | username and password in a file. 107 | ```sh 108 | # echo "https://wallabag.example.com 2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo 4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g root sV5G/aTjYRcNkSlTOsZuB78YG." > ./wallindle.cfg 109 | ``` 110 | 111 | ## Uploading to kindle 112 | 113 | Do as you want : by command line, file manager or even ssh it doesn't matter. 114 | Storing both wallindle binary and configuration in the same folders as 115 | epub is a good option. Assuming that, your binary and config file are now 116 | stored in /mnt/base-us/documents/ 117 | 118 | ## Testing on kindle 119 | ```sh 120 | $ ssh root@192.168.15.244 121 | 122 | 123 | Welcome to Kindle! 124 | 125 | root@192.168.15.244's password: 126 | ################################################# 127 | # N O T I C E * N O T I C E * N O T I C E # 128 | ################################################# 129 | Rootfs is mounted read-only. Invoke mntroot rw to 130 | switch back to a writable rootfs. 131 | ################################################# 132 | 133 | [root@kindle root]# cp /mnt/base-us/documents/wallindle* /tmp 134 | 135 | [root@kindle root]# cd /tmp 136 | 137 | [root@kindle tmp]# ls -alh wallindle* 138 | -rwxr-xr-x 1 root root 192.8k Aug 19 14:34 wallindle 139 | -rwxr-xr-x 1 root root 168 Aug 19 14:34 wallindle.cfg 140 | 141 | [root@kindle tmp]# ./wallindle 142 | token_count = 11 143 | (...) 144 | created_at= 2017-08-19T 145 | 146 | MischiefManaged! 147 | ``` 148 | If you see "MischiefManaged!" then everything goes well :-). Otherwise 149 | you will see an error you can retrieve inside code source or by pinging me 150 | on [twitter](https://twitter.com/cekagedev) 151 | 152 | 153 | In my case 7 files were downloaded : 154 | 155 | ```sh 156 | [root@kindle tmp]# ls -alh /mnt/base-us/documents/wallabag/*mobi 157 | -rwxr-xr-x 1 root root 113.4k Aug 19 14:35 /mnt/base-us/documents/wallabag/0000010f.mobi 158 | -rwxr-xr-x 1 root root 4.5k Aug 19 14:35 /mnt/base-us/documents/wallabag/00000111.mobi 159 | -rwxr-xr-x 1 root root 1.5k Aug 19 14:35 /mnt/base-us/documents/wallabag/00000112.mobi 160 | -rwxr-xr-x 1 root root 3.6k Aug 19 14:35 /mnt/base-us/documents/wallabag/00000125.mobi 161 | -rwxr-xr-x 1 root root 3.3k Aug 19 14:35 /mnt/base-us/documents/wallabag/00000126.mobi 162 | -rwxr-xr-x 1 root root 9.4k Aug 19 14:35 /mnt/base-us/documents/wallabag/00000127.mobi 163 | -rwxr-xr-x 1 root root 16.0k Aug 19 14:35 /mnt/base-us/documents/wallabag/00000128.mobi 164 | ``` 165 | 166 | # Let's the kindle fetching by itself 167 | Now this is time for bad to really bad advices. Letting a non Amazon approved 168 | binary running by itself is a really bad idea. But : 169 | 170 | - Even if kindle has other user accounts, only root can write on Document 171 | folders. In every case, wallindle must runs with root privilege, and it's a 172 | very bad news. 173 | 174 | - None of the file stored on Document can be executed. No known workaround with 175 | the kernel 2.6.31 running in the Kindle. 176 | 177 | - The Document directory is a fat32 filesystem, there is no rights management 178 | with it. Every files can be rw by owner and r by group and others. 179 | 180 | ## Bad idea #1 : running as root a non protected binary 181 | 182 | *Keep in mind, it's a really bad idea : this create a very serious security 183 | issue* 184 | 185 | 1. Storing wallindle and wallindle.cfg on Documents 186 | 2. Copy both from Documents to /tmp/ 187 | 3. Launch wallindle ( /mnt/base-us/documents/wallabag directory in hardcoded ) 188 | 4. crontab that 189 | 190 | ```sh 191 | $ ssh root@192.168.15.244 192 | 193 | 194 | Welcome to Kindle! 195 | 196 | root@192.168.15.244's password: 197 | ################################################# 198 | # N O T I C E * N O T I C E * N O T I C E # 199 | ################################################# 200 | Rootfs is mounted read-only. Invoke mntroot rw to 201 | switch back to a writable rootfs. 202 | ################################################# 203 | 204 | [root@kindle root]# mntroot rw 205 | system: I mntroot:def:Making root filesystem writeable 206 | /dev/mmcblk0p1 on / type ext3 (rw,noatime,nodiratime) 207 | 208 | 209 | [root@kindle root]# nano /etc/crontab/root 210 | ``` 211 | Add this line : 212 | 213 | ``` 214 | 00 */4 * * * (cd /mnt/us/documents/ && (./wallindle > wallindle.log)) 215 | ``` 216 | 217 | Verify the new content 218 | ```sh 219 | [root@kindle root]# cat /etc/crontab/root 220 | */15 * * * * /usr/sbin/checkpmond 221 | */15 * * * * /usr/sbin/tinyrot 222 | */60 * * * * /usr/sbin/loginfo tmpfs 223 | */60 * * * * /usr/sbin/loginfo localVars 224 | */60 * * * * /usr/sbin/loginfo memusedump 225 | */15 * * * * /usr/sbin/loginfo powerdcheck 226 | 227 | 00 */4 * * * (cd /mnt/us/documents/ && (./wallindle > wallindle.log)) 228 | ``` 229 | 230 | Remount / read only : 231 | ```sh 232 | [root@kindle root]# mntroot ro 233 | system: I mntroot:def:Making root filesystem read-only 234 | /dev/mmcblk0p1 on / type ext3 (ro,noatime,nodiratime) 235 | 236 | ``` 237 | 238 | Restart cron agent : 239 | ```sh 240 | [root@kindle root]# pkill crond && /usr/sbin/crond -c /etc/crontab/ 241 | ``` 242 | 243 | Remember kids, this file will be run as root. Do you *really* want to transform 244 | your kindle in a piece of garbage ? I'm sure not. 245 | 246 | ## Bad idea #2 : running as root a protected binary 247 | 248 | Same as the first bad idea except you don't store wallindle in 249 | /mnt/base-us/documents/ but elsewhere on the rom of the kindle. In this case 250 | nobody can alter the binary but do you really want to alter the rom file 251 | structure list ? 252 | -------------------------------------------------------------------------------- /configmanager.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include "shared.h" 27 | #include "configmanager.h" 28 | 29 | #include 30 | 31 | static wd_result _WBConfigGet(WBoAuthCred* wbcred, const char* cfg_filename); 32 | static wd_result _WBReadConfiguration(const char* filename, off_t filesize, 33 | char** filecontent); 34 | static void _TestConfigPrint(const WBoAuthCred* wbc); 35 | static bool _TestConfigCompare(WBoAuthCred* wb1, WBoAuthCred* wb2); 36 | 37 | /* 38 | * Function: WBConfigGet 39 | * ---------------------------- 40 | * Writes to wbcred data found on DEFAULT_CONFIG_FILE 41 | * 42 | * wbcred: a pointer to a WBoAuthCred 43 | * 44 | * returns: WNDL_OK if wbcred is update. WNDL_ERROR otherwise. 45 | */ 46 | wd_result WBConfigGet(WBoAuthCred* wbcred) { 47 | return _WBConfigGet(wbcred, DEFAULT_CONFIG_FILE); 48 | } 49 | 50 | /* 51 | * Function: GetFileSize 52 | * ---------------------------- 53 | * Returns the file size and if size is in a min-max interval. 54 | * Interval is defined by MIN_CONFFILE_SIZE and MAX_CONFFILE_SIZE 55 | * 56 | * filename: file name (absolute or relative) 57 | * check_min_max: if true size is checked 58 | * 59 | * returns: the size, in bytes, of the file. Or -1 if file size 60 | * isn't found (missing file, wrong filename,…) or if file size 61 | * isn't inside interval. 62 | */ 63 | off_t GetFileSize(const char* filename, bool check_min_max) { 64 | 65 | off_t result = -1; 66 | struct stat fs_stat; 67 | 68 | // Checks if an error occurs when retrieving file size 69 | if (0 != stat(filename, &fs_stat)) { 70 | fprintf(stderr, "Cannot determine sizeof %s:%s\n", filename, strerror(errno)); 71 | } else if (check_min_max && (MIN_CONFFILE_SIZE > fs_stat.st_size 72 | || MAX_CONFFILE_SIZE < fs_stat.st_size)) { 73 | fprintf(stderr, 74 | "Suspiscious size for %s : MIN_CONFFILE_SIZE=%d MAX_CONFFILE_SIZE=%d\n", 75 | filename, MIN_CONFFILE_SIZE, MAX_CONFFILE_SIZE); 76 | } else { 77 | // No previous error then store file size in result 78 | result = fs_stat.st_size; 79 | } 80 | 81 | return result; 82 | } 83 | 84 | /* 85 | * Function: WBConfigInit 86 | * ---------------------------- 87 | * Initialize all fields of a WBoAuthCred object. 88 | * 89 | * wbc: a pointer to a WBoAuthCred 90 | * 91 | * returns: WNDL_OK if wbcred is initialized. And 92 | * WNDL_ERROR otherwise. 93 | */ 94 | wd_result WBConfigInit(WBoAuthCred* wbc) { 95 | #define CHECKFIELD(FD) result &= (NULL!=wbc->FD); 96 | #define INITFIELD(FD) wbc->FD=calloc(1, sizeof(char)); CHECKFIELD(FD) 97 | //#define INITFIELD(FD) wbc->FD=calloc(0, sizeof(char)); 98 | bool result = true; 99 | INITFIELD(wallabag_host); 100 | INITFIELD(client_id); 101 | INITFIELD(client_secret); 102 | INITFIELD(username); 103 | INITFIELD(password); 104 | INITFIELD(token); 105 | return result ? WNDL_OK : WNDL_ERROR ; 106 | #undef INITFIELD 107 | #undef CHECKFIELD 108 | } 109 | 110 | /* 111 | * Function: WBConfigCleanup 112 | * ---------------------------- 113 | * Free and nullize all fields of a WBoAuthCred object. 114 | * 115 | * wbc: a pointer to a WBoAuthCred 116 | * 117 | * returns: nothing. 118 | */ 119 | void WBConfigCleanup(WBoAuthCred* wbc) { 120 | #define FREEFIELD(FD) free(wbc->FD);wbc->FD=NULL; 121 | FREEFIELD(wallabag_host); 122 | FREEFIELD(client_id); 123 | FREEFIELD(client_secret); 124 | FREEFIELD(username); 125 | FREEFIELD(password); 126 | FREEFIELD(token); 127 | #undef FREEFIELD 128 | } 129 | 130 | /* 131 | * Function: WBConfigForgeoAuthURL 132 | * ---------------------------- 133 | * Build the oAuth2 url based on authentication 134 | * credentials passed in parameters. 135 | * 136 | * wbc: a pointer to a WBoAuthCred 137 | * 138 | * returns: an url if everything is ok. A null pointer 139 | * otherwise 140 | */ 141 | char* WBConfigForgeoAuthURL(WBoAuthCred* wbc) { 142 | 143 | char* url; 144 | size_t url_size; 145 | 146 | // Calculate size of url using MASK minus 5* "%s" 147 | // plus the length of wbs fields 148 | url_size = ( sizeof(AUTH_URL_MASK) - 5 * ( sizeof("%s") - 1) 149 | + strlen(wbc->wallabag_host) + strlen(wbc->client_id) 150 | + strlen(wbc->client_secret) + strlen(wbc->username) 151 | + strlen(wbc->password)) * sizeof(char); 152 | 153 | // Allocate with zeros 154 | url = calloc(url_size + 1, sizeof(char)); 155 | 156 | if (NULL == url) { 157 | // If fails, warns user on stderr 158 | fprintf(stderr, "Cannot allocate oauth url\n"); 159 | } else { 160 | // Store in "url" the mask and parameters 161 | int sprinted = snprintf(url, url_size, AUTH_URL_MASK, wbc->wallabag_host, 162 | wbc->client_id, wbc->client_secret, wbc->username, 163 | wbc->password); 164 | 165 | // Checking if snprintf works as expected (size > 1) 166 | if (1 > sprinted) { 167 | // If fails : warns, frees & nulls url 168 | fprintf(stderr, "Cannot snprintf oauth url\n"); 169 | free(url); 170 | url = NULL; 171 | } 172 | } 173 | 174 | return url; 175 | } 176 | 177 | wd_result _WBReadConfiguration(const char* filename, off_t filesize, 178 | char** filecontent) { 179 | size_t totalread; 180 | FILE* f = fopen(filename, "r"); 181 | 182 | if (NULL == f) { 183 | fprintf(stderr, "Cannot open %s:%s\n", filename, strerror(errno)); 184 | return WNDL_ERROR; 185 | } 186 | 187 | totalread = fread(*filecontent, sizeof(char), 188 | (size_t)filesize, f); 189 | fclose(f); 190 | 191 | if ( sizeof(char) > totalread) { 192 | fprintf(stderr, "Cannot determine sizeof %s:%s\n", filename, 193 | strerror(errno)); 194 | return WNDL_ERROR; 195 | } 196 | 197 | return WNDL_OK; 198 | } 199 | 200 | 201 | static void _FieldFindAndSave(bool* proceed, char* src, char** dest, 202 | const char* fieldname) { 203 | if (proceed) { 204 | const char* delim = " "; 205 | char* token = strtok(src, delim); 206 | bool result = (NULL != token); 207 | 208 | if (result) { 209 | size_t last_char_pos = strlen(token) - 1; 210 | 211 | if ('\n' == token[last_char_pos]) { 212 | token[last_char_pos] = 0; 213 | } 214 | 215 | StoreContent(token, strlen(token), dest); 216 | } else { 217 | fprintf(stderr, "Cannot determine field %s\n", fieldname); 218 | } 219 | 220 | *proceed = result; 221 | } 222 | 223 | } 224 | 225 | static wd_result _WBConfigGet(WBoAuthCred* wbcred, const char* cfg_filename) { 226 | 227 | off_t filesize; 228 | char* filecontent; 229 | bool must_continue = true; 230 | 231 | 232 | filesize = GetFileSize(cfg_filename, true); 233 | 234 | if (-1 == filesize) { 235 | return WNDL_ERROR; 236 | } 237 | 238 | filecontent = calloc(filesize + 1UL, sizeof(char)); 239 | 240 | if (NULL == filecontent) { 241 | return WNDL_ERROR; 242 | } 243 | 244 | if (must_continue) { 245 | int readresult = _WBReadConfiguration(cfg_filename, filesize, &filecontent); 246 | must_continue = (WNDL_OK == readresult); 247 | _FieldFindAndSave(&must_continue, filecontent, &wbcred->wallabag_host, 248 | "wallabag_host"); 249 | _FieldFindAndSave(&must_continue, NULL, &wbcred->client_id, "client_id"); 250 | _FieldFindAndSave(&must_continue, NULL, &wbcred->client_secret, 251 | "client_secret"); 252 | _FieldFindAndSave(&must_continue, NULL, &wbcred->username, "username"); 253 | _FieldFindAndSave(&must_continue, NULL, &wbcred->password, "password"); 254 | 255 | } 256 | 257 | free(filecontent); 258 | 259 | return must_continue ? WNDL_OK : WNDL_ERROR; 260 | } 261 | 262 | static void _TestConfigPrint(const WBoAuthCred* wbc) { 263 | #define PRINTFIELD(FD) printf("wbc->%s(%"PRIuPTR"o.)=%s\n", #FD, strlen(wbc->FD), wbc->FD) 264 | PRINTFIELD(wallabag_host); 265 | PRINTFIELD(client_id); 266 | PRINTFIELD(client_secret); 267 | PRINTFIELD(username); 268 | PRINTFIELD(password); 269 | PRINTFIELD(token); 270 | #undef PRINTFIELD 271 | } 272 | 273 | static bool _TestConfigCompare(WBoAuthCred* wb1, WBoAuthCred* wb2) { 274 | #define CHECKFIELD(FD) result &= (0 == strcmp(wb1->FD, wb2->FD)) 275 | bool result = true; 276 | CHECKFIELD(wallabag_host); 277 | CHECKFIELD(client_id); 278 | CHECKFIELD(client_secret); 279 | CHECKFIELD(username); 280 | CHECKFIELD(password); 281 | CHECKFIELD(token); 282 | return result; 283 | #undef CHECKFIELD 284 | } 285 | 286 | -------------------------------------------------------------------------------- /configmanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #ifndef CONFIGMANAGER_H 18 | #define CONFIGMANAGER_H 19 | 20 | #include 21 | 22 | #include "shared.h" 23 | 24 | typedef struct WBoAuthCred { 25 | char* wallabag_host; 26 | char* client_id; 27 | char* client_secret; 28 | char* username; 29 | char* password; 30 | char* token; 31 | } WBoAuthCred; 32 | 33 | wd_result WBConfigGet(WBoAuthCred* wbcred); 34 | 35 | off_t GetFileSize(const char* filename, bool check_min_max); 36 | 37 | wd_result WBConfigInit(WBoAuthCred* wbc); 38 | void WBConfigCleanup(WBoAuthCred* wbc); 39 | 40 | char* WBConfigForgeoAuthURL(WBoAuthCred* wbc); 41 | 42 | #endif//CONFIGMANAGER_H 43 | -------------------------------------------------------------------------------- /download_kindle_lib.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DEST=lib/curlkindle/lib 4 | SRC=/usr/lib 5 | KINDLEIP=192.168.15.244 6 | 7 | for lib in ssl curl crypt 8 | do 9 | scp root@${KINDLEIP}:${SRC}/lib${lib}*so ${DEST} 10 | done; 11 | 12 | -------------------------------------------------------------------------------- /entries_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | #include "shared.h" 25 | #include "configmanager.h" 26 | #include "entries_common.h" 27 | 28 | char* WBEntryFetchingURL(WBoAuthCred* wbc) { 29 | 30 | char* url; 31 | int last_week_in_utc; 32 | int sprinted; 33 | 34 | // TODO(k) Check real size instead of MAX_INT_STRLEN 35 | const size_t url_size = ( sizeof(FETCH_ENTRIES_MASK) - 1 //themasksize1 36 | - (2 * ( sizeof("%s") - 1) + ( sizeof("%d") - 1)) //minusformats 37 | + MAX_INT_STRLEN//plusmaxintsize 38 | + strlen(wbc->wallabag_host) 39 | + strlen(wbc->token) + 1 40 | ) * sizeof(char); 41 | 42 | url = calloc(url_size + 1, sizeof(char)); 43 | 44 | if (NULL == url) { 45 | fprintf(stderr, "Cannot allocate fetching url"); 46 | return NULL; 47 | } 48 | 49 | last_week_in_utc = time(NULL) - UP_TO_X_DAYS * 24 * 60 * 60; 50 | sprinted = snprintf(url, url_size, FETCH_ENTRIES_MASK, 51 | wbc->wallabag_host, wbc->token, last_week_in_utc); 52 | 53 | if (1 > sprinted) { 54 | fprintf(stderr, "Cannot snprintf fetching url"); 55 | free(url); 56 | return NULL; 57 | } 58 | 59 | return url; 60 | } 61 | 62 | void WBEntryCleaup(WBEntry* wbe) { 63 | free(wbe->created_at); 64 | wbe->created_at = NULL; 65 | wbe->id = 0; 66 | } 67 | -------------------------------------------------------------------------------- /entries_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #ifndef ENTRIES_COMMON_H_INCLUDED 18 | #define ENTRIES_COMMON_H_INCLUDED 19 | 20 | #include "configmanager.h" 21 | 22 | typedef struct WBEntry { 23 | bool is_archived; 24 | bool is_starred; 25 | unsigned long int id; 26 | char* created_at; 27 | } WBEntry; 28 | 29 | char* WBEntryFetchingURL(WBoAuthCred* wbc); 30 | 31 | void WBEntryCleaup(WBEntry* wbe); 32 | 33 | #endif//ENTRIES_COMMON_H_INCLUDED 34 | -------------------------------------------------------------------------------- /http_request.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | // With Original code from Daniel Stenberg et al. 18 | // https://curl.haxx.se/libcurl/c/getinmemory.html 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include "perform_entries.h" 29 | #include "http_request.h" 30 | 31 | #include "shared.h" 32 | 33 | /* 34 | * Function: WriteMemoryCallback 35 | * ---------------------------- 36 | * Append "n" bytes of "content" to "userp". With "n" 37 | * computed with the size of the content to write. 38 | * *Original code from libcurl !* 39 | * 40 | * contents: elements to be written 41 | * size: size of one element to write 42 | * nmemb: the count of elements to write 43 | * userp: a MemoryStruct to be appended 44 | * 45 | * returns: the amount of element written 46 | */ 47 | size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, 48 | void* userp) { 49 | size_t realsize = size * nmemb; 50 | struct MemoryStruct* mem = (struct MemoryStruct*)userp; 51 | 52 | mem->memory = realloc(mem->memory, mem->size + realsize + 1); 53 | 54 | if (mem->memory == NULL) { 55 | // out of memory! 56 | fprintf(stderr, "not enough memory (realloc returned NULL)\n"); 57 | return 0; 58 | } 59 | 60 | // Append "realsize" bytes of "content" to memory 61 | memcpy(&(mem->memory[mem->size]), contents, realsize); 62 | 63 | mem->size += realsize; // update MemoryStruct size 64 | mem->memory[mem->size] = 0; // Add null terminator (String) 65 | 66 | return realsize; 67 | } 68 | 69 | 70 | /* 71 | * Function: GetJSON 72 | * ---------------------------- 73 | * Download content at "url" and store it on jsonresponse 74 | * 75 | * url: an url (probably http://domain.tld/ 76 | * jsonresponse: a MemoryStruct to be filled 77 | * 78 | * returns: WNDL_OK if everything goes well, WNDL_ERROR otherwise 79 | */ 80 | wd_result GetJSON(const char* url, const void* jsonresponse) { 81 | // TODO(k) change proto as follows : char* GetJSON(const char* url) 82 | // printf(" url transmise : %s\n", url); 83 | 84 | CURL* curl_handle; 85 | CURLcode res; 86 | 87 | curl_global_init(CURL_GLOBAL_ALL); 88 | /* init the curl session */ 89 | curl_handle = curl_easy_init(); 90 | /* specify URL to get */ 91 | curl_easy_setopt(curl_handle, CURLOPT_URL, url); 92 | /* send all data to this function */ 93 | 94 | curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); 95 | /* we pass our 'chunk' struct to the callback function */ 96 | curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, jsonresponse); 97 | /* some servers don't like requests that are made without a user-agent field, so we provide one */ 98 | curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, WALLINDLE_USERAGENT); 99 | /* getit! */ 100 | res = curl_easy_perform(curl_handle); 101 | 102 | /* check for error s*/ 103 | if (CURLE_OK != res) { 104 | fprintf(stderr, "curl_easy_perform() failed: %d %s\n", res, 105 | curl_easy_strerror(res)); 106 | } 107 | 108 | /* clean up curl stuff*/ 109 | curl_easy_cleanup(curl_handle); 110 | /* we're done with libcurl, so clean it up*/ 111 | curl_global_cleanup(); 112 | 113 | return (CURLE_OK == res) ? WNDL_OK : WNDL_ERROR; 114 | } 115 | 116 | /* 117 | * Function: GetEbook 118 | * ---------------------------- 119 | * Download an url content to a file. 120 | * 121 | * url: an url (probably http://domain.tld/ 122 | * filename: a file (will be overwritten) 123 | * 124 | * returns: WNDL_OK if everything goes well, WNDL_ERROR otherwise 125 | */ 126 | wd_result GetEbook(const char* url, const char* filename) { 127 | 128 | // Boilerplate for curl stuff 129 | CURL* curl; 130 | wd_result result = WNDL_ERROR; 131 | 132 | if (IsEbookAlreadyDownloaded(filename)) { 133 | return WNDL_OK; 134 | } 135 | 136 | curl = curl_easy_init(); 137 | 138 | if (NULL != curl) { 139 | // Open the file "filename" 140 | FILE* file_handle = fopen(filename, "wb"); 141 | 142 | // Curl set-up, url, callback & User Agent 143 | curl_easy_setopt(curl, CURLOPT_URL, url); 144 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); 145 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, file_handle); 146 | curl_easy_setopt(curl, CURLOPT_USERAGENT, WALLINDLE_USERAGENT); 147 | 148 | // perform curl 149 | CURLcode res = curl_easy_perform(curl); 150 | 151 | if (CURLE_OK == res) { // If no error it's ok 152 | result = WNDL_OK; 153 | } else { 154 | // if not, print to stderr 155 | fprintf(stderr, "curl_easy_perform() failed : %s\n", curl_easy_strerror(res)); 156 | } 157 | 158 | // close opened file 159 | fclose(file_handle); 160 | } 161 | 162 | // classic way to clean up a curl 163 | curl_easy_cleanup(curl); 164 | return result; 165 | } 166 | -------------------------------------------------------------------------------- /http_request.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | // With Original code from Daniel Stenberg et al. 18 | // https://curl.haxx.se/libcurl/c/getinmemory.html 19 | 20 | #ifndef HTTP_REQUEST_H 21 | #define HTTP_REQUEST_H 22 | 23 | #include 24 | 25 | #include "shared.h" 26 | 27 | typedef struct MemoryStruct { 28 | char* memory; 29 | size_t size; 30 | } MemoryStruct; 31 | 32 | size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, 33 | void* userp); 34 | 35 | wd_result GetJSON(const char* url, const void* jsonresponse); 36 | 37 | wd_result GetEbook(const char* url, const char* filename); 38 | 39 | #endif/*HTTP_REQUEST_H*/ 40 | -------------------------------------------------------------------------------- /json_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | 18 | //With Original code from Serge Zaitsev http://zserge.com 19 | //https://github.com/zserge/jsmn/blob/master/example/simple.c 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include "shared.h" 30 | #include "configmanager.h" 31 | 32 | #include "json_common.h" 33 | 34 | static char* _WBReadFile(const char* filename, bool isConfig); 35 | 36 | unsigned int _GetTokenCountExt(const char* jsonresponse, jsmntok_t* tokens, 37 | unsigned int maxtoken) { 38 | 39 | int token_count; 40 | jsmn_parser parser; 41 | jsmn_init(&parser); 42 | 43 | if (NULL == jsonresponse) { 44 | return 0; 45 | } 46 | 47 | // jsmn_parse in "count mode" 48 | token_count = jsmn_parse(&parser, jsonresponse, strlen(jsonresponse), 49 | tokens, maxtoken); 50 | 51 | // printf(" token_count = %d\n", token_count); 52 | 53 | if (token_count < 0) { 54 | fprintf(stderr, "Failed to parse JSON : %d\n", token_count); 55 | token_count = 0; 56 | } 57 | 58 | return token_count; 59 | } 60 | 61 | unsigned int _GetTokenCount(const char* jsonresponse) { 62 | return _GetTokenCountExt(jsonresponse, NULL, 0); 63 | } 64 | 65 | wd_result _JsonEquivTo(const char* json, const jsmntok_t* 66 | tok, const char* s) { 67 | bool result; 68 | 69 | result = (tok->type == JSMN_STRING); 70 | result &= ((int)strlen(s) == (tok->end - tok->start)); 71 | result &= (0 == strncmp(json + tok->start, s, tok->end - tok->start)); 72 | 73 | return (result ? WNDL_OK : WNDL_ERROR); 74 | } 75 | 76 | static char* _WBReadFile(const char* filename, bool isConfig) { 77 | off_t filesize; 78 | size_t totalread; 79 | 80 | char* filecontent; 81 | FILE* file_handle; 82 | 83 | file_handle = fopen(filename, "r"); 84 | 85 | if (NULL == file_handle) { 86 | fprintf(stderr, "Cannot open %s:%s\n", filename, strerror(errno)); 87 | return NULL; 88 | } 89 | 90 | filesize = GetFileSize(filename, isConfig); 91 | filecontent = calloc((size_t)filesize + 1UL, sizeof(char)); 92 | 93 | if (NULL == filecontent) { 94 | fprintf(stderr, "Cannot allocate %jd for filecontent\n", (intmax_t) filesize); 95 | fclose(file_handle); 96 | return NULL; 97 | } 98 | 99 | totalread = fread(filecontent, sizeof(char), 100 | (size_t)filesize, file_handle); 101 | fclose(file_handle); 102 | 103 | if ( sizeof(char) > totalread) { 104 | fprintf(stderr, "Too small content %" PRIuPTR " bytes\n", totalread); 105 | free(filecontent); 106 | return NULL; 107 | } 108 | 109 | return filecontent; 110 | } 111 | 112 | // For testing purpose 113 | static char* _TestReadEntriesJsonFile(const char* filename) { 114 | return _WBReadFile(filename, false); 115 | } 116 | 117 | // For testing purpose 118 | static char* _TestReadoAuthJsonFile(const char* filename) { 119 | return _WBReadFile(filename, true); 120 | } 121 | -------------------------------------------------------------------------------- /json_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #ifndef JSON_COMMON_PARSE_H_INCLUDED 18 | #define JSON_COMMON_PARSE_H_INCLUDED 19 | 20 | #include "./lib/jsmn/jsmn.h" 21 | #include "shared.h" 22 | 23 | // TODO(k) Add test 24 | wd_result _JsonEquivTo(const char* json, const jsmntok_t* 25 | tok, const char* s); 26 | 27 | unsigned int _GetTokenCount(const char* jsonresponse); 28 | unsigned int _GetTokenCountExt(const char* jsonresponse, jsmntok_t* tokens, 29 | unsigned int maxtoken); 30 | 31 | #endif//JSON_COMMON_PARSE_H_INCLUDED 32 | 33 | -------------------------------------------------------------------------------- /json_entries_parse.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | // With Original code from Serge Zaitsev http://zserge.com 18 | // https://github.com/zserge/jsmn/blob/master/example/simple.c 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include "entries_common.h" 29 | #include "json_common.h" 30 | #include "perform_entries.h" 31 | 32 | #include "configmanager.h" 33 | 34 | #include "json_entries_parse.h" 35 | 36 | static jsmntok_t* _AllocateTokens(const char* jsoncontent, size_t count); 37 | static wd_result _BuildTokens(const char* jsonresponse, jsmntok_t* tokens, 38 | int token_count); 39 | static WBEntry* _ExtractEntries(long int max_entries, jsmntok_t* tokens, 40 | const char* jsonresponse, int token_count, int index); 41 | static void _FindKeysAndStore(jsmntok_t* tokens, const char* jsonresponse, 42 | int index, unsigned int entry_index, WBEntry* entries); 43 | static wd_result _GetJsonKeyPosition(const char* jsoncontent, 44 | const jsmntok_t* tokens, unsigned int max_token_count, const char* key, 45 | jsmntype_t tokentype, unsigned int* from); 46 | static unsigned int _GetMaxEntries(jsmntok_t* tokens, const char* jsonresponse, 47 | int token_count, unsigned int* pindex); 48 | static long int _GetMaxEntriesField(jsmntok_t* tokens, const char* jsonresponse, 49 | unsigned int token_count, unsigned int* pindex, const char* field); 50 | 51 | // TODO(k) rething usage of must_continue (previously a return NULL) 52 | WBEntry* JsonGetEntries(const char* jsonresponse) { 53 | WBEntry* entries = NULL; 54 | unsigned int max_entries; 55 | unsigned int index = 1; 56 | jsmntok_t* tokens = NULL; 57 | bool must_continue; 58 | 59 | // Compute how many tokens we will need to get the whole JSON 60 | const unsigned int token_count = _GetTokenCount(jsonresponse); 61 | 62 | // If token_count is zero then we must not continue 63 | must_continue = (0 != token_count); 64 | 65 | if (must_continue) { 66 | // Dynamically allocate memory for tokens array 67 | tokens = _AllocateTokens(jsonresponse, (size_t) token_count); 68 | // If tokens is null it's because a problem occurs and we 69 | // must not continue. 70 | must_continue = (NULL != tokens); 71 | } 72 | 73 | if (must_continue) { 74 | must_continue = (WNDL_OK == _BuildTokens(jsonresponse, tokens, token_count)); 75 | } 76 | 77 | if (must_continue) { 78 | max_entries = _GetMaxEntries(tokens, jsonresponse, token_count, &index); 79 | must_continue = (0 != max_entries); 80 | 81 | _GetJsonKeyPosition(jsonresponse, tokens, token_count, 82 | "_embedded", JSMN_OBJECT, &index); 83 | must_continue &= (token_count != index); 84 | 85 | _GetJsonKeyPosition(jsonresponse, tokens, token_count, 86 | "items", JSMN_ARRAY, &index); 87 | must_continue &= (token_count != index); 88 | 89 | } 90 | 91 | if (must_continue) { 92 | index += 2; 93 | entries = _ExtractEntries(max_entries, tokens, jsonresponse, 94 | token_count, index); 95 | } 96 | 97 | free(tokens); 98 | return entries; 99 | } 100 | 101 | static jsmntok_t* _AllocateTokens(const char* jsoncontent, size_t count) { 102 | 103 | jsmntok_t* tokens = calloc(count + 1, sizeof(jsmntok_t)); 104 | 105 | if (NULL == tokens) { return NULL; } 106 | 107 | jsmn_parser parser; 108 | jsmn_init(&parser); 109 | int token_count = jsmn_parse(&parser, jsoncontent, strlen(jsoncontent), 110 | tokens, count); 111 | 112 | if ((0 > token_count) || ((int) count != token_count)) { 113 | free(tokens); 114 | tokens = NULL; 115 | } 116 | 117 | return tokens; 118 | } 119 | 120 | // TODO(k): return WB ERROR / OK 121 | static wd_result _GetJsonKeyPosition(const char* jsoncontent, 122 | const jsmntok_t* tokens, unsigned int max_token_count, const char* key, 123 | jsmntype_t tokentype, unsigned int* from) { 124 | bool is_key_present; 125 | 126 | do { 127 | // Check key exists 128 | is_key_present = (WNDL_OK == _JsonEquivTo(jsoncontent, &tokens[*from], 129 | key)); 130 | // and if next item 131 | ++(*from); 132 | 133 | // is a tokentype 134 | is_key_present &= (tokens[*from].type == tokentype); 135 | } while (*from < max_token_count && !is_key_present); 136 | 137 | //if (*from == max_token_count) { 138 | if (!is_key_present) { 139 | fprintf(stderr, "%s expected but not found\n", key); 140 | } 141 | 142 | return is_key_present ? WNDL_OK : WNDL_ERROR; 143 | } 144 | 145 | //static void _TokenPrint(jsmntok_t t) { 146 | // printf("Type=%d, start=%d, end=%d, size=%d\n", t.type, t.start, t.end, t.size); 147 | //} 148 | 149 | 150 | static long int _GetMaxEntriesField(jsmntok_t* tokens, const char* jsonresponse, 151 | unsigned int token_count, unsigned int* pindex, const char* field) { 152 | unsigned int index = *pindex; // pointer to index 153 | char* str_value = NULL; 154 | long int numeric_value; 155 | 156 | // Reaching field 157 | _GetJsonKeyPosition(jsonresponse, tokens, token_count, field, JSMN_PRIMITIVE, 158 | &index); 159 | 160 | // if token_count is reached, then 161 | if (index == token_count) { 162 | // field is not found so print error & return zero 163 | fprintf(stderr, "'%s' field not found\n", field); 164 | return 0; 165 | } 166 | 167 | // Copy content in str_value 168 | StoreContent(jsonresponse + tokens[index].start, 169 | MIN(tokens[index].end - tokens[index].start, 4), &str_value); 170 | // Convert in 10-basis to numeric_value 171 | 172 | // TODO(k): better check strtol 173 | numeric_value = strtol(str_value, NULL, 10); 174 | // Releasing str_value 175 | free(str_value); 176 | return numeric_value; 177 | } 178 | 179 | static unsigned int _GetMaxEntries(jsmntok_t* tokens, const char* jsonresponse, 180 | int token_count, unsigned int* pindex) { 181 | 182 | long int total; 183 | long int pages; // Number of pages 184 | 185 | // Reaching key "pages" 186 | pages = _GetMaxEntriesField(tokens, jsonresponse, token_count, pindex, "pages"); 187 | 188 | // Checking if page number 189 | if (0 >= pages) { 190 | fprintf(stderr, "pages primitive >1 expected\n"); 191 | return 0; 192 | } 193 | 194 | // Reaching key "total" 195 | total = _GetMaxEntriesField(tokens, jsonresponse, token_count, pindex, "total"); 196 | 197 | if (0 >= pages) { 198 | fprintf(stderr, "'total' primitive >1 expected\n"); 199 | return 0; 200 | } 201 | 202 | return ceil( (double) MIN(total, MAXIMUM_ENTRIES) / pages); 203 | } 204 | 205 | static wd_result _BuildTokens(const char* jsonresponse, jsmntok_t* tokens, 206 | int token_count) { 207 | 208 | wd_result result = WNDL_OK; 209 | jsmn_parser parser; 210 | jsmn_init(&parser); 211 | int parse_status = jsmn_parse(&parser, jsonresponse, strlen(jsonresponse), 212 | tokens, 213 | token_count); 214 | 215 | if (0 > parse_status ) { 216 | fprintf(stderr, "bad json structure\n"); 217 | result = WNDL_ERROR; 218 | } else { 219 | if (JSMN_OBJECT != tokens[0].type) { 220 | fprintf(stderr, "Object expected\n"); 221 | result = WNDL_ERROR; 222 | } 223 | } 224 | 225 | return result; 226 | } 227 | 228 | 229 | 230 | //static void _printtoken(jsmntok_t token, const char* json) { 231 | // printf("Token start:%d end:%d size:%d type:%d --> %.*s\n", token.start, 232 | // token.end, token.size, token.type, 30, json + token.start); 233 | //} 234 | 235 | static WBEntry* _ExtractEntries(long int max_entries, jsmntok_t* tokens, 236 | const char* jsonresponse, int token_count, int index) { 237 | #define NEXT_ITEM ++index 238 | 239 | WBEntry* entries; 240 | unsigned int entry_index; 241 | 242 | entries = calloc(max_entries + 1, sizeof(WBEntry)); 243 | 244 | if (NULL == entries) 245 | { return NULL; } 246 | 247 | entry_index = 0; 248 | 249 | do { // new entry 250 | entries[entry_index] = (WBEntry) {.id = -1, .created_at = NULL}; 251 | --index; 252 | int item_end = tokens[index].end; 253 | 254 | // _printtoken(tokens[index], jsonresponse); 255 | // printf("** entry_index= %d : item_end = %d\n",entry_index, tokens[index].end); 256 | do { 257 | // printf("--> index = %d\n",index); 258 | _FindKeysAndStore(tokens, jsonresponse, index, entry_index, entries); 259 | 260 | NEXT_ITEM; 261 | // _printtoken(tokens[index], jsonresponse); 262 | // NEXT_ITEM; 263 | // _printtoken(tokens[index], jsonresponse); 264 | } while (index < token_count && tokens[index].start < item_end); 265 | 266 | // printf("\n** entry_index= %d --> jsonresponse + tokens[%d].start = %.*s\n",entry_index, index, 40,jsonresponse+ tokens[index].start); 267 | ++entry_index; 268 | NEXT_ITEM; 269 | // _printtoken(tokens[index], jsonresponse); 270 | 271 | } while (index < token_count && entry_index < max_entries); 272 | 273 | entries[entry_index] = (WBEntry) {.id = 0, .created_at = NULL}; 274 | 275 | return entries; 276 | #undef NEXT_ITEM 277 | } 278 | 279 | static void _FindKeysAndStore(jsmntok_t* tokens, const char* jsonresponse, 280 | int index, unsigned int entry_index, WBEntry* entries) { 281 | 282 | // get size of tokens by subtitute start field to end field 283 | unsigned int token_size = tokens[index].end - tokens[index].start + 1; 284 | 285 | if (WNDL_OK == _JsonEquivTo(jsonresponse, &tokens[index], "id")) { 286 | char* value = NULL; 287 | // printf("StoreContent : jsonresponse+delta = %.*s ",20, jsonresponse+tokens[index].start); 288 | // Point to next token : value of "id" 289 | ++index; 290 | // Store token content inside "value" 291 | StoreContent(jsonresponse + tokens[index].start, token_size, &value); 292 | // printf(" &value = %s ", value); 293 | // Convert string value in entries field "id" 294 | entries[entry_index].id = strtol(value, NULL, 10); 295 | // printf(" entries[%d].id = %lu\n", entry_index, entries[entry_index].id); 296 | 297 | // No more usage of value : releasing 298 | free(value); 299 | } else if (WNDL_OK == _JsonEquivTo(jsonresponse, &tokens[index], "created_at")) { 300 | // Point to next token : value of "id" 301 | ++index; 302 | // Store token content inside "created_at" 303 | StoreContent(jsonresponse + tokens[index].start, token_size, 304 | &entries[entry_index].created_at); 305 | } 306 | } 307 | 308 | -------------------------------------------------------------------------------- /json_entries_parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #ifndef JSON_PARSE_H_INCLUDED 18 | #define JSON_PARSE_H_INCLUDED 19 | 20 | #include "entries_common.h" 21 | 22 | WBEntry* JsonGetEntries(const char* jsonresponse); 23 | 24 | #endif//JSON_PARSE_H_INCLUDED 25 | 26 | -------------------------------------------------------------------------------- /json_oauth_parse.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | // With original code from Serge Zaitsev http://zserge.com 18 | // https://github.com/zserge/jsmn/blob/master/example/simple.c 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "./lib/jsmn/jsmn.h" 25 | 26 | 27 | #include "json_common.h" 28 | #include "json_oauth_parse.h" 29 | #include "shared.h" 30 | 31 | /* 32 | * Function: ExtractoAuth2Token 33 | * ---------------------------- 34 | * Returns oAuth2 token stored in a json. 35 | * 36 | * jsonobject: a json object as string 37 | * 38 | * returns: a pointer to the token (a string) 39 | */ 40 | char* ExtractoAuth2Token(const char* jsonobject) { 41 | int token_count; 42 | unsigned int index; 43 | char* result = NULL; 44 | 45 | /* We expect no more than 20 tokens */ 46 | jsmntok_t tokens[20]; 47 | 48 | // Get the count of tokens in jsonobject 49 | token_count = _GetTokenCountExt(jsonobject, tokens, 50 | sizeof(tokens) / sizeof(tokens[0])); 51 | 52 | // If something went wrong 53 | if (0 >= token_count) { 54 | // quit here 55 | return NULL; 56 | } 57 | 58 | // We are sure token_count is always positive ! 59 | 60 | if (JSMN_OBJECT != tokens[0].type) { 61 | // if it's not an object : error then quit. 62 | fprintf(stderr, "Object expected\n"); 63 | return NULL; 64 | } 65 | 66 | /* Loop over all keys of the root object */ 67 | for (index = 1; index < (unsigned int) token_count; ++index) { 68 | // Check if we encounter a token named "access_token" 69 | if (WNDL_OK == _JsonEquivTo(jsonobject, &tokens[index], "access_token")) { 70 | char* extracted_token = NULL; 71 | // So the usefull content is next token 72 | ++index; 73 | /* We may use strndup() to fetch string value */ 74 | size_t stringlength = (size_t)(tokens[index].end - tokens[index].start); 75 | 76 | // Store content of token in extracted_token and checks result 77 | if (WNDL_OK == StoreContent(jsonobject + tokens[index].start, 78 | stringlength, &extracted_token)) { 79 | // if ok return a pointer to the token 80 | result = extracted_token; 81 | break; 82 | } else { 83 | // otherwise, free token 84 | free(extracted_token); 85 | } 86 | } 87 | } 88 | 89 | // Here nothing usefull found -> return an error (NULL) 90 | return result; 91 | } 92 | -------------------------------------------------------------------------------- /json_oauth_parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #ifndef JSON_OAUTH_PARSE_H_INCLUDED 18 | #define JSON_OAUTH_PARSE_H_INCLUDED 19 | 20 | char* ExtractoAuth2Token(const char* jsonobject); 21 | 22 | #endif //JSON_OAUTH_PARSE_H_INCLUDED 23 | 24 | -------------------------------------------------------------------------------- /lib/curlkindle/bin/curl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cekage/wallindle/1ffef0033b764e459e4dea0a5defb3f2776c9165/lib/curlkindle/bin/curl -------------------------------------------------------------------------------- /lib/curlkindle/bin/curl-config: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | #*************************************************************************** 3 | # _ _ ____ _ 4 | # Project ___| | | | _ \| | 5 | # / __| | | | |_) | | 6 | # | (__| |_| | _ <| |___ 7 | # \___|\___/|_| \_\_____| 8 | # 9 | # Copyright (C) 2001 - 2010, Daniel Stenberg, , et al. 10 | # 11 | # This software is licensed as described in the file COPYING, which 12 | # you should have received as part of this distribution. The terms 13 | # are also available at http://curl.haxx.se/docs/copyright.html. 14 | # 15 | # You may opt to use, copy, modify, merge, publish, distribute and/or sell 16 | # copies of the Software, and permit persons to whom the Software is 17 | # furnished to do so, under the terms of the COPYING file. 18 | # 19 | # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20 | # KIND, either express or implied. 21 | # 22 | ########################################################################### 23 | 24 | prefix=./lib/curlkindle 25 | exec_prefix=${prefix} 26 | includedir=${prefix}/include 27 | 28 | usage() 29 | { 30 | cat <, et al. 12 | * 13 | * This software is licensed as described in the file COPYING, which 14 | * you should have received as part of this distribution. The terms 15 | * are also available at http://curl.haxx.se/docs/copyright.html. 16 | * 17 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 18 | * copies of the Software, and permit persons to whom the Software is 19 | * furnished to do so, under the terms of the COPYING file. 20 | * 21 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 22 | * KIND, either express or implied. 23 | * 24 | ***************************************************************************/ 25 | 26 | /* ================================================================ */ 27 | /* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ 28 | /* ================================================================ */ 29 | 30 | /* 31 | * NOTE 1: 32 | * ------- 33 | * 34 | * Nothing in this file is intended to be modified or adjusted by the 35 | * curl library user nor by the curl library builder. 36 | * 37 | * If you think that something actually needs to be changed, adjusted 38 | * or fixed in this file, then, report it on the libcurl development 39 | * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ 40 | * 41 | * This header file shall only export symbols which are 'curl' or 'CURL' 42 | * prefixed, otherwise public name space would be polluted. 43 | * 44 | * NOTE 2: 45 | * ------- 46 | * 47 | * Right now you might be staring at file include/curl/curlbuild.h.in or 48 | * at file include/curl/curlbuild.h, this is due to the following reason: 49 | * 50 | * On systems capable of running the configure script, the configure process 51 | * will overwrite the distributed include/curl/curlbuild.h file with one that 52 | * is suitable and specific to the library being configured and built, which 53 | * is generated from the include/curl/curlbuild.h.in template file. 54 | * 55 | */ 56 | 57 | /* ================================================================ */ 58 | /* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ 59 | /* ================================================================ */ 60 | 61 | #ifdef CURL_SIZEOF_LONG 62 | # error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" 63 | Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined 64 | #endif 65 | 66 | #ifdef CURL_TYPEOF_CURL_SOCKLEN_T 67 | # error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" 68 | Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined 69 | #endif 70 | 71 | #ifdef CURL_SIZEOF_CURL_SOCKLEN_T 72 | # error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" 73 | Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined 74 | #endif 75 | 76 | #ifdef CURL_TYPEOF_CURL_OFF_T 77 | # error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" 78 | Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined 79 | #endif 80 | 81 | #ifdef CURL_FORMAT_CURL_OFF_T 82 | # error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" 83 | Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined 84 | #endif 85 | 86 | #ifdef CURL_FORMAT_CURL_OFF_TU 87 | # error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" 88 | Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined 89 | #endif 90 | 91 | #ifdef CURL_FORMAT_OFF_T 92 | # error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" 93 | Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined 94 | #endif 95 | 96 | #ifdef CURL_SIZEOF_CURL_OFF_T 97 | # error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" 98 | Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined 99 | #endif 100 | 101 | #ifdef CURL_SUFFIX_CURL_OFF_T 102 | # error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" 103 | Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined 104 | #endif 105 | 106 | #ifdef CURL_SUFFIX_CURL_OFF_TU 107 | # error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" 108 | Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined 109 | #endif 110 | 111 | /* ================================================================ */ 112 | /* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ 113 | /* ================================================================ */ 114 | 115 | /* Configure process defines this to 1 when it finds out that system */ 116 | /* header file ws2tcpip.h must be included by the external interface. */ 117 | /* #undef CURL_PULL_WS2TCPIP_H */ 118 | #ifdef CURL_PULL_WS2TCPIP_H 119 | # ifndef WIN32_LEAN_AND_MEAN 120 | # define WIN32_LEAN_AND_MEAN 121 | # endif 122 | # include 123 | # include 124 | # include 125 | #endif 126 | 127 | /* Configure process defines this to 1 when it finds out that system */ 128 | /* header file sys/types.h must be included by the external interface. */ 129 | #define CURL_PULL_SYS_TYPES_H 1 130 | #ifdef CURL_PULL_SYS_TYPES_H 131 | # include 132 | #endif 133 | 134 | /* Configure process defines this to 1 when it finds out that system */ 135 | /* header file stdint.h must be included by the external interface. */ 136 | #define CURL_PULL_STDINT_H 1 137 | #ifdef CURL_PULL_STDINT_H 138 | # include 139 | #endif 140 | 141 | /* Configure process defines this to 1 when it finds out that system */ 142 | /* header file inttypes.h must be included by the external interface. */ 143 | #define CURL_PULL_INTTYPES_H 1 144 | #ifdef CURL_PULL_INTTYPES_H 145 | # include 146 | #endif 147 | 148 | /* Configure process defines this to 1 when it finds out that system */ 149 | /* header file sys/socket.h must be included by the external interface. */ 150 | #define CURL_PULL_SYS_SOCKET_H 1 151 | #ifdef CURL_PULL_SYS_SOCKET_H 152 | # include 153 | #endif 154 | 155 | /* The size of `long', as computed by sizeof. */ 156 | #define CURL_SIZEOF_LONG 4 157 | 158 | /* Integral data type used for curl_socklen_t. */ 159 | #define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t 160 | 161 | /* The size of `curl_socklen_t', as computed by sizeof. */ 162 | #define CURL_SIZEOF_CURL_SOCKLEN_T 4 163 | 164 | /* Data type definition of curl_socklen_t. */ 165 | typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; 166 | 167 | /* Signed integral data type used for curl_off_t. */ 168 | #define CURL_TYPEOF_CURL_OFF_T int64_t 169 | 170 | /* Data type definition of curl_off_t. */ 171 | typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; 172 | 173 | /* curl_off_t formatting string directive without "%" conversion specifier. */ 174 | #define CURL_FORMAT_CURL_OFF_T "lld" 175 | 176 | /* unsigned curl_off_t formatting string without "%" conversion specifier. */ 177 | #define CURL_FORMAT_CURL_OFF_TU "llu" 178 | 179 | /* curl_off_t formatting string directive with "%" conversion specifier. */ 180 | #define CURL_FORMAT_OFF_T "%lld" 181 | 182 | /* The size of `curl_off_t', as computed by sizeof. */ 183 | #define CURL_SIZEOF_CURL_OFF_T 8 184 | 185 | /* curl_off_t constant suffix. */ 186 | #define CURL_SUFFIX_CURL_OFF_T LL 187 | 188 | /* unsigned curl_off_t constant suffix. */ 189 | #define CURL_SUFFIX_CURL_OFF_TU ULL 190 | 191 | #endif /* __CURL_CURLBUILD_H */ 192 | -------------------------------------------------------------------------------- /lib/curlkindle/include/curl/curlrules.h: -------------------------------------------------------------------------------- 1 | #ifndef __CURL_CURLRULES_H 2 | #define __CURL_CURLRULES_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at http://curl.haxx.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | ***************************************************************************/ 24 | 25 | /* ================================================================ */ 26 | /* COMPILE TIME SANITY CHECKS */ 27 | /* ================================================================ */ 28 | 29 | /* 30 | * NOTE 1: 31 | * ------- 32 | * 33 | * All checks done in this file are intentionally placed in a public 34 | * header file which is pulled by curl/curl.h when an application is 35 | * being built using an already built libcurl library. Additionally 36 | * this file is also included and used when building the library. 37 | * 38 | * If compilation fails on this file it is certainly sure that the 39 | * problem is elsewhere. It could be a problem in the curlbuild.h 40 | * header file, or simply that you are using different compilation 41 | * settings than those used to build the library. 42 | * 43 | * Nothing in this file is intended to be modified or adjusted by the 44 | * curl library user nor by the curl library builder. 45 | * 46 | * Do not deactivate any check, these are done to make sure that the 47 | * library is properly built and used. 48 | * 49 | * You can find further help on the libcurl development mailing list: 50 | * http://cool.haxx.se/mailman/listinfo/curl-library/ 51 | * 52 | * NOTE 2 53 | * ------ 54 | * 55 | * Some of the following compile time checks are based on the fact 56 | * that the dimension of a constant array can not be a negative one. 57 | * In this way if the compile time verification fails, the compilation 58 | * will fail issuing an error. The error description wording is compiler 59 | * dependent but it will be quite similar to one of the following: 60 | * 61 | * "negative subscript or subscript is too large" 62 | * "array must have at least one element" 63 | * "-1 is an illegal array size" 64 | * "size of array is negative" 65 | * 66 | * If you are building an application which tries to use an already 67 | * built libcurl library and you are getting this kind of errors on 68 | * this file, it is a clear indication that there is a mismatch between 69 | * how the library was built and how you are trying to use it for your 70 | * application. Your already compiled or binary library provider is the 71 | * only one who can give you the details you need to properly use it. 72 | */ 73 | 74 | /* 75 | * Verify that some macros are actually defined. 76 | */ 77 | 78 | #ifndef CURL_SIZEOF_LONG 79 | # error "CURL_SIZEOF_LONG definition is missing!" 80 | Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing 81 | #endif 82 | 83 | #ifndef CURL_TYPEOF_CURL_SOCKLEN_T 84 | # error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" 85 | Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing 86 | #endif 87 | 88 | #ifndef CURL_SIZEOF_CURL_SOCKLEN_T 89 | # error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" 90 | Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing 91 | #endif 92 | 93 | #ifndef CURL_TYPEOF_CURL_OFF_T 94 | # error "CURL_TYPEOF_CURL_OFF_T definition is missing!" 95 | Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing 96 | #endif 97 | 98 | #ifndef CURL_FORMAT_CURL_OFF_T 99 | # error "CURL_FORMAT_CURL_OFF_T definition is missing!" 100 | Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing 101 | #endif 102 | 103 | #ifndef CURL_FORMAT_CURL_OFF_TU 104 | # error "CURL_FORMAT_CURL_OFF_TU definition is missing!" 105 | Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing 106 | #endif 107 | 108 | #ifndef CURL_FORMAT_OFF_T 109 | # error "CURL_FORMAT_OFF_T definition is missing!" 110 | Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing 111 | #endif 112 | 113 | #ifndef CURL_SIZEOF_CURL_OFF_T 114 | # error "CURL_SIZEOF_CURL_OFF_T definition is missing!" 115 | Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing 116 | #endif 117 | 118 | #ifndef CURL_SUFFIX_CURL_OFF_T 119 | # error "CURL_SUFFIX_CURL_OFF_T definition is missing!" 120 | Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing 121 | #endif 122 | 123 | #ifndef CURL_SUFFIX_CURL_OFF_TU 124 | # error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" 125 | Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing 126 | #endif 127 | 128 | /* 129 | * Macros private to this header file. 130 | */ 131 | 132 | #define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 133 | 134 | #define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 135 | 136 | /* 137 | * Verify that the size previously defined and expected for long 138 | * is the same as the one reported by sizeof() at compile time. 139 | */ 140 | 141 | typedef char 142 | __curl_rule_01__ 143 | [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; 144 | 145 | /* 146 | * Verify that the size previously defined and expected for 147 | * curl_off_t is actually the the same as the one reported 148 | * by sizeof() at compile time. 149 | */ 150 | 151 | typedef char 152 | __curl_rule_02__ 153 | [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; 154 | 155 | /* 156 | * Verify at compile time that the size of curl_off_t as reported 157 | * by sizeof() is greater or equal than the one reported for long 158 | * for the current compilation. 159 | */ 160 | 161 | typedef char 162 | __curl_rule_03__ 163 | [CurlchkszGE(curl_off_t, long)]; 164 | 165 | /* 166 | * Verify that the size previously defined and expected for 167 | * curl_socklen_t is actually the the same as the one reported 168 | * by sizeof() at compile time. 169 | */ 170 | 171 | typedef char 172 | __curl_rule_04__ 173 | [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; 174 | 175 | /* 176 | * Verify at compile time that the size of curl_socklen_t as reported 177 | * by sizeof() is greater or equal than the one reported for int for 178 | * the current compilation. 179 | */ 180 | 181 | typedef char 182 | __curl_rule_05__ 183 | [CurlchkszGE(curl_socklen_t, int)]; 184 | 185 | /* ================================================================ */ 186 | /* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ 187 | /* ================================================================ */ 188 | 189 | /* 190 | * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow 191 | * these to be visible and exported by the external libcurl interface API, 192 | * while also making them visible to the library internals, simply including 193 | * setup.h, without actually needing to include curl.h internally. 194 | * If some day this section would grow big enough, all this should be moved 195 | * to its own header file. 196 | */ 197 | 198 | /* 199 | * Figure out if we can use the ## preprocessor operator, which is supported 200 | * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ 201 | * or __cplusplus so we need to carefully check for them too. 202 | */ 203 | 204 | #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ 205 | defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ 206 | defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ 207 | defined(__ILEC400__) 208 | /* This compiler is believed to have an ISO compatible preprocessor */ 209 | #define CURL_ISOCPP 210 | #else 211 | /* This compiler is believed NOT to have an ISO compatible preprocessor */ 212 | #undef CURL_ISOCPP 213 | #endif 214 | 215 | /* 216 | * Macros for minimum-width signed and unsigned curl_off_t integer constants. 217 | */ 218 | 219 | #if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) 220 | # define __CURL_OFF_T_C_HLPR2(x) x 221 | # define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) 222 | # define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ 223 | __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) 224 | # define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ 225 | __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) 226 | #else 227 | # ifdef CURL_ISOCPP 228 | # define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix 229 | # else 230 | # define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix 231 | # endif 232 | # define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) 233 | # define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) 234 | # define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) 235 | #endif 236 | 237 | /* 238 | * Get rid of macros private to this header file. 239 | */ 240 | 241 | #undef CurlchkszEQ 242 | #undef CurlchkszGE 243 | 244 | /* 245 | * Get rid of macros not intended to exist beyond this point. 246 | */ 247 | 248 | #undef CURL_PULL_WS2TCPIP_H 249 | #undef CURL_PULL_SYS_TYPES_H 250 | #undef CURL_PULL_SYS_SOCKET_H 251 | #undef CURL_PULL_STDINT_H 252 | #undef CURL_PULL_INTTYPES_H 253 | 254 | #undef CURL_TYPEOF_CURL_SOCKLEN_T 255 | #undef CURL_TYPEOF_CURL_OFF_T 256 | 257 | #ifdef CURL_NO_OLDIES 258 | #undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */ 259 | #endif 260 | 261 | #endif /* __CURL_CURLRULES_H */ 262 | -------------------------------------------------------------------------------- /lib/curlkindle/include/curl/curlver.h: -------------------------------------------------------------------------------- 1 | #ifndef __CURL_CURLVER_H 2 | #define __CURL_CURLVER_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at http://curl.haxx.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | ***************************************************************************/ 24 | 25 | /* This header file contains nothing but libcurl version info, generated by 26 | a script at release-time. This was made its own header file in 7.11.2 */ 27 | 28 | /* This is the global package copyright */ 29 | #define LIBCURL_COPYRIGHT "1996 - 2010 Daniel Stenberg, ." 30 | 31 | /* This is the version number of the libcurl package from which this header 32 | file origins: */ 33 | #define LIBCURL_VERSION "7.21.4" 34 | 35 | /* The numeric version number is also available "in parts" by using these 36 | defines: */ 37 | #define LIBCURL_VERSION_MAJOR 7 38 | #define LIBCURL_VERSION_MINOR 21 39 | #define LIBCURL_VERSION_PATCH 4 40 | 41 | /* This is the numeric version of the libcurl version number, meant for easier 42 | parsing and comparions by programs. The LIBCURL_VERSION_NUM define will 43 | always follow this syntax: 44 | 45 | 0xXXYYZZ 46 | 47 | Where XX, YY and ZZ are the main version, release and patch numbers in 48 | hexadecimal (using 8 bits each). All three numbers are always represented 49 | using two digits. 1.2 would appear as "0x010200" while version 9.11.7 50 | appears as "0x090b07". 51 | 52 | This 6-digit (24 bits) hexadecimal number does not show pre-release number, 53 | and it is always a greater number in a more recent release. It makes 54 | comparisons with greater than and less than work. 55 | */ 56 | #define LIBCURL_VERSION_NUM 0x071504 57 | 58 | /* 59 | * This is the date and time when the full source package was created. The 60 | * timestamp is not stored in git, as the timestamp is properly set in the 61 | * tarballs by the maketgz script. 62 | * 63 | * The format of the date should follow this template: 64 | * 65 | * "Mon Feb 12 11:35:33 UTC 2007" 66 | */ 67 | #define LIBCURL_TIMESTAMP "Thu Feb 17 12:19:40 UTC 2011" 68 | 69 | #endif /* __CURL_CURLVER_H */ 70 | -------------------------------------------------------------------------------- /lib/curlkindle/include/curl/easy.h: -------------------------------------------------------------------------------- 1 | #ifndef __CURL_EASY_H 2 | #define __CURL_EASY_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at http://curl.haxx.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | ***************************************************************************/ 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | CURL_EXTERN CURL *curl_easy_init(void); 29 | CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); 30 | CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); 31 | CURL_EXTERN void curl_easy_cleanup(CURL *curl); 32 | 33 | /* 34 | * NAME curl_easy_getinfo() 35 | * 36 | * DESCRIPTION 37 | * 38 | * Request internal information from the curl session with this function. The 39 | * third argument MUST be a pointer to a long, a pointer to a char * or a 40 | * pointer to a double (as the documentation describes elsewhere). The data 41 | * pointed to will be filled in accordingly and can be relied upon only if the 42 | * function returns CURLE_OK. This function is intended to get used *AFTER* a 43 | * performed transfer, all results from this function are undefined until the 44 | * transfer is completed. 45 | */ 46 | CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); 47 | 48 | 49 | /* 50 | * NAME curl_easy_duphandle() 51 | * 52 | * DESCRIPTION 53 | * 54 | * Creates a new curl session handle with the same options set for the handle 55 | * passed in. Duplicating a handle could only be a matter of cloning data and 56 | * options, internal state info and things like persistant connections cannot 57 | * be transfered. It is useful in multithreaded applications when you can run 58 | * curl_easy_duphandle() for each new thread to avoid a series of identical 59 | * curl_easy_setopt() invokes in every thread. 60 | */ 61 | CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); 62 | 63 | /* 64 | * NAME curl_easy_reset() 65 | * 66 | * DESCRIPTION 67 | * 68 | * Re-initializes a CURL handle to the default values. This puts back the 69 | * handle to the same state as it was in when it was just created. 70 | * 71 | * It does keep: live connections, the Session ID cache, the DNS cache and the 72 | * cookies. 73 | */ 74 | CURL_EXTERN void curl_easy_reset(CURL *curl); 75 | 76 | /* 77 | * NAME curl_easy_recv() 78 | * 79 | * DESCRIPTION 80 | * 81 | * Receives data from the connected socket. Use after successful 82 | * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. 83 | */ 84 | CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, 85 | size_t *n); 86 | 87 | /* 88 | * NAME curl_easy_send() 89 | * 90 | * DESCRIPTION 91 | * 92 | * Sends data over the connected socket. Use after successful 93 | * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. 94 | */ 95 | CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, 96 | size_t buflen, size_t *n); 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /lib/curlkindle/include/curl/mprintf.h: -------------------------------------------------------------------------------- 1 | #ifndef __CURL_MPRINTF_H 2 | #define __CURL_MPRINTF_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at http://curl.haxx.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | ***************************************************************************/ 24 | 25 | #include 26 | #include /* needed for FILE */ 27 | 28 | #include "curl.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | CURL_EXTERN int curl_mprintf(const char *format, ...); 35 | CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); 36 | CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); 37 | CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, 38 | const char *format, ...); 39 | CURL_EXTERN int curl_mvprintf(const char *format, va_list args); 40 | CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); 41 | CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); 42 | CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, 43 | const char *format, va_list args); 44 | CURL_EXTERN char *curl_maprintf(const char *format, ...); 45 | CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); 46 | 47 | #ifdef _MPRINTF_REPLACE 48 | # undef printf 49 | # undef fprintf 50 | # undef sprintf 51 | # undef vsprintf 52 | # undef snprintf 53 | # undef vprintf 54 | # undef vfprintf 55 | # undef vsnprintf 56 | # undef aprintf 57 | # undef vaprintf 58 | # define printf curl_mprintf 59 | # define fprintf curl_mfprintf 60 | #ifdef CURLDEBUG 61 | /* When built with CURLDEBUG we define away the sprintf() functions since we 62 | don't want internal code to be using them */ 63 | # define sprintf sprintf_was_used 64 | # define vsprintf vsprintf_was_used 65 | #else 66 | # define sprintf curl_msprintf 67 | # define vsprintf curl_mvsprintf 68 | #endif 69 | # define snprintf curl_msnprintf 70 | # define vprintf curl_mvprintf 71 | # define vfprintf curl_mvfprintf 72 | # define vsnprintf curl_mvsnprintf 73 | # define aprintf curl_maprintf 74 | # define vaprintf curl_mvaprintf 75 | #endif 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | #endif /* __CURL_MPRINTF_H */ 82 | -------------------------------------------------------------------------------- /lib/curlkindle/include/curl/multi.h: -------------------------------------------------------------------------------- 1 | #ifndef __CURL_MULTI_H 2 | #define __CURL_MULTI_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at http://curl.haxx.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | ***************************************************************************/ 24 | /* 25 | This is an "external" header file. Don't give away any internals here! 26 | 27 | GOALS 28 | 29 | o Enable a "pull" interface. The application that uses libcurl decides where 30 | and when to ask libcurl to get/send data. 31 | 32 | o Enable multiple simultaneous transfers in the same thread without making it 33 | complicated for the application. 34 | 35 | o Enable the application to select() on its own file descriptors and curl's 36 | file descriptors simultaneous easily. 37 | 38 | */ 39 | 40 | /* 41 | * This header file should not really need to include "curl.h" since curl.h 42 | * itself includes this file and we expect user applications to do #include 43 | * without the need for especially including multi.h. 44 | * 45 | * For some reason we added this include here at one point, and rather than to 46 | * break existing (wrongly written) libcurl applications, we leave it as-is 47 | * but with this warning attached. 48 | */ 49 | #include "curl.h" 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | typedef void CURLM; 56 | 57 | typedef enum { 58 | CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or 59 | curl_multi_socket*() soon */ 60 | CURLM_OK, 61 | CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ 62 | CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ 63 | CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ 64 | CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ 65 | CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ 66 | CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ 67 | CURLM_LAST 68 | } CURLMcode; 69 | 70 | /* just to make code nicer when using curl_multi_socket() you can now check 71 | for CURLM_CALL_MULTI_SOCKET too in the same style it works for 72 | curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ 73 | #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM 74 | 75 | typedef enum { 76 | CURLMSG_NONE, /* first, not used */ 77 | CURLMSG_DONE, /* This easy handle has completed. 'result' contains 78 | the CURLcode of the transfer */ 79 | CURLMSG_LAST /* last, not used */ 80 | } CURLMSG; 81 | 82 | struct CURLMsg { 83 | CURLMSG msg; /* what this message means */ 84 | CURL *easy_handle; /* the handle it concerns */ 85 | union { 86 | void *whatever; /* message-specific data */ 87 | CURLcode result; /* return code for transfer */ 88 | } data; 89 | }; 90 | typedef struct CURLMsg CURLMsg; 91 | 92 | /* 93 | * Name: curl_multi_init() 94 | * 95 | * Desc: inititalize multi-style curl usage 96 | * 97 | * Returns: a new CURLM handle to use in all 'curl_multi' functions. 98 | */ 99 | CURL_EXTERN CURLM *curl_multi_init(void); 100 | 101 | /* 102 | * Name: curl_multi_add_handle() 103 | * 104 | * Desc: add a standard curl handle to the multi stack 105 | * 106 | * Returns: CURLMcode type, general multi error code. 107 | */ 108 | CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, 109 | CURL *curl_handle); 110 | 111 | /* 112 | * Name: curl_multi_remove_handle() 113 | * 114 | * Desc: removes a curl handle from the multi stack again 115 | * 116 | * Returns: CURLMcode type, general multi error code. 117 | */ 118 | CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, 119 | CURL *curl_handle); 120 | 121 | /* 122 | * Name: curl_multi_fdset() 123 | * 124 | * Desc: Ask curl for its fd_set sets. The app can use these to select() or 125 | * poll() on. We want curl_multi_perform() called as soon as one of 126 | * them are ready. 127 | * 128 | * Returns: CURLMcode type, general multi error code. 129 | */ 130 | CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, 131 | fd_set *read_fd_set, 132 | fd_set *write_fd_set, 133 | fd_set *exc_fd_set, 134 | int *max_fd); 135 | 136 | /* 137 | * Name: curl_multi_perform() 138 | * 139 | * Desc: When the app thinks there's data available for curl it calls this 140 | * function to read/write whatever there is right now. This returns 141 | * as soon as the reads and writes are done. This function does not 142 | * require that there actually is data available for reading or that 143 | * data can be written, it can be called just in case. It returns 144 | * the number of handles that still transfer data in the second 145 | * argument's integer-pointer. 146 | * 147 | * Returns: CURLMcode type, general multi error code. *NOTE* that this only 148 | * returns errors etc regarding the whole multi stack. There might 149 | * still have occurred problems on invidual transfers even when this 150 | * returns OK. 151 | */ 152 | CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, 153 | int *running_handles); 154 | 155 | /* 156 | * Name: curl_multi_cleanup() 157 | * 158 | * Desc: Cleans up and removes a whole multi stack. It does not free or 159 | * touch any individual easy handles in any way. We need to define 160 | * in what state those handles will be if this function is called 161 | * in the middle of a transfer. 162 | * 163 | * Returns: CURLMcode type, general multi error code. 164 | */ 165 | CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); 166 | 167 | /* 168 | * Name: curl_multi_info_read() 169 | * 170 | * Desc: Ask the multi handle if there's any messages/informationals from 171 | * the individual transfers. Messages include informationals such as 172 | * error code from the transfer or just the fact that a transfer is 173 | * completed. More details on these should be written down as well. 174 | * 175 | * Repeated calls to this function will return a new struct each 176 | * time, until a special "end of msgs" struct is returned as a signal 177 | * that there is no more to get at this point. 178 | * 179 | * The data the returned pointer points to will not survive calling 180 | * curl_multi_cleanup(). 181 | * 182 | * The 'CURLMsg' struct is meant to be very simple and only contain 183 | * very basic informations. If more involved information is wanted, 184 | * we will provide the particular "transfer handle" in that struct 185 | * and that should/could/would be used in subsequent 186 | * curl_easy_getinfo() calls (or similar). The point being that we 187 | * must never expose complex structs to applications, as then we'll 188 | * undoubtably get backwards compatibility problems in the future. 189 | * 190 | * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out 191 | * of structs. It also writes the number of messages left in the 192 | * queue (after this read) in the integer the second argument points 193 | * to. 194 | */ 195 | CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, 196 | int *msgs_in_queue); 197 | 198 | /* 199 | * Name: curl_multi_strerror() 200 | * 201 | * Desc: The curl_multi_strerror function may be used to turn a CURLMcode 202 | * value into the equivalent human readable error string. This is 203 | * useful for printing meaningful error messages. 204 | * 205 | * Returns: A pointer to a zero-terminated error message. 206 | */ 207 | CURL_EXTERN const char *curl_multi_strerror(CURLMcode); 208 | 209 | /* 210 | * Name: curl_multi_socket() and 211 | * curl_multi_socket_all() 212 | * 213 | * Desc: An alternative version of curl_multi_perform() that allows the 214 | * application to pass in one of the file descriptors that have been 215 | * detected to have "action" on them and let libcurl perform. 216 | * See man page for details. 217 | */ 218 | #define CURL_POLL_NONE 0 219 | #define CURL_POLL_IN 1 220 | #define CURL_POLL_OUT 2 221 | #define CURL_POLL_INOUT 3 222 | #define CURL_POLL_REMOVE 4 223 | 224 | #define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD 225 | 226 | #define CURL_CSELECT_IN 0x01 227 | #define CURL_CSELECT_OUT 0x02 228 | #define CURL_CSELECT_ERR 0x04 229 | 230 | typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ 231 | curl_socket_t s, /* socket */ 232 | int what, /* see above */ 233 | void *userp, /* private callback 234 | pointer */ 235 | void *socketp); /* private socket 236 | pointer */ 237 | /* 238 | * Name: curl_multi_timer_callback 239 | * 240 | * Desc: Called by libcurl whenever the library detects a change in the 241 | * maximum number of milliseconds the app is allowed to wait before 242 | * curl_multi_socket() or curl_multi_perform() must be called 243 | * (to allow libcurl's timed events to take place). 244 | * 245 | * Returns: The callback should return zero. 246 | */ 247 | typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ 248 | long timeout_ms, /* see above */ 249 | void *userp); /* private callback 250 | pointer */ 251 | 252 | CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, 253 | int *running_handles); 254 | 255 | CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, 256 | curl_socket_t s, 257 | int ev_bitmask, 258 | int *running_handles); 259 | 260 | CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, 261 | int *running_handles); 262 | 263 | #ifndef CURL_ALLOW_OLD_MULTI_SOCKET 264 | /* This macro below was added in 7.16.3 to push users who recompile to use 265 | the new curl_multi_socket_action() instead of the old curl_multi_socket() 266 | */ 267 | #define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) 268 | #endif 269 | 270 | /* 271 | * Name: curl_multi_timeout() 272 | * 273 | * Desc: Returns the maximum number of milliseconds the app is allowed to 274 | * wait before curl_multi_socket() or curl_multi_perform() must be 275 | * called (to allow libcurl's timed events to take place). 276 | * 277 | * Returns: CURLM error code. 278 | */ 279 | CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, 280 | long *milliseconds); 281 | 282 | #undef CINIT /* re-using the same name as in curl.h */ 283 | 284 | #ifdef CURL_ISOCPP 285 | #define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num 286 | #else 287 | /* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ 288 | #define LONG CURLOPTTYPE_LONG 289 | #define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT 290 | #define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT 291 | #define OFF_T CURLOPTTYPE_OFF_T 292 | #define CINIT(name,type,number) CURLMOPT_/**/name = type + number 293 | #endif 294 | 295 | typedef enum { 296 | /* This is the socket callback function pointer */ 297 | CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), 298 | 299 | /* This is the argument passed to the socket callback */ 300 | CINIT(SOCKETDATA, OBJECTPOINT, 2), 301 | 302 | /* set to 1 to enable pipelining for this multi handle */ 303 | CINIT(PIPELINING, LONG, 3), 304 | 305 | /* This is the timer callback function pointer */ 306 | CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), 307 | 308 | /* This is the argument passed to the timer callback */ 309 | CINIT(TIMERDATA, OBJECTPOINT, 5), 310 | 311 | /* maximum number of entries in the connection cache */ 312 | CINIT(MAXCONNECTS, LONG, 6), 313 | 314 | CURLMOPT_LASTENTRY /* the last unused */ 315 | } CURLMoption; 316 | 317 | 318 | /* 319 | * Name: curl_multi_setopt() 320 | * 321 | * Desc: Sets options for the multi handle. 322 | * 323 | * Returns: CURLM error code. 324 | */ 325 | CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, 326 | CURLMoption option, ...); 327 | 328 | 329 | /* 330 | * Name: curl_multi_assign() 331 | * 332 | * Desc: This function sets an association in the multi handle between the 333 | * given socket and a private pointer of the application. This is 334 | * (only) useful for curl_multi_socket uses. 335 | * 336 | * Returns: CURLM error code. 337 | */ 338 | CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, 339 | curl_socket_t sockfd, void *sockp); 340 | 341 | #ifdef __cplusplus 342 | } /* end of extern "C" */ 343 | #endif 344 | 345 | #endif 346 | -------------------------------------------------------------------------------- /lib/curlkindle/include/curl/stdcheaders.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDC_HEADERS_H 2 | #define __STDC_HEADERS_H 3 | /*************************************************************************** 4 | * _ _ ____ _ 5 | * Project ___| | | | _ \| | 6 | * / __| | | | |_) | | 7 | * | (__| |_| | _ <| |___ 8 | * \___|\___/|_| \_\_____| 9 | * 10 | * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. 11 | * 12 | * This software is licensed as described in the file COPYING, which 13 | * you should have received as part of this distribution. The terms 14 | * are also available at http://curl.haxx.se/docs/copyright.html. 15 | * 16 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 17 | * copies of the Software, and permit persons to whom the Software is 18 | * furnished to do so, under the terms of the COPYING file. 19 | * 20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 | * KIND, either express or implied. 22 | * 23 | ***************************************************************************/ 24 | 25 | #include 26 | 27 | size_t fread (void *, size_t, size_t, FILE *); 28 | size_t fwrite (const void *, size_t, size_t, FILE *); 29 | 30 | int strcasecmp(const char *, const char *); 31 | int strncasecmp(const char *, const char *, size_t); 32 | 33 | #endif /* __STDC_HEADERS_H */ 34 | -------------------------------------------------------------------------------- /lib/curlkindle/include/curl/types.h: -------------------------------------------------------------------------------- 1 | /* not used */ 2 | -------------------------------------------------------------------------------- /lib/curlkindle/lib/pkgconfig/libcurl.pc: -------------------------------------------------------------------------------- 1 | #*************************************************************************** 2 | # _ _ ____ _ 3 | # Project ___| | | | _ \| | 4 | # / __| | | | |_) | | 5 | # | (__| |_| | _ <| |___ 6 | # \___|\___/|_| \_\_____| 7 | # 8 | # Copyright (C) 2004 - 2007, Daniel Stenberg, , et al. 9 | # 10 | # This software is licensed as described in the file COPYING, which 11 | # you should have received as part of this distribution. The terms 12 | # are also available at http://curl.haxx.se/docs/copyright.html. 13 | # 14 | # You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 | # copies of the Software, and permit persons to whom the Software is 16 | # furnished to do so, under the terms of the COPYING file. 17 | # 18 | # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 | # KIND, either express or implied. 20 | # 21 | ########################################################################### 22 | 23 | # This should most probably benefit from getting a "Requires:" field added 24 | # dynamically by configure. 25 | # 26 | prefix=/tmp/curl/buildk 27 | exec_prefix=${prefix} 28 | libdir=${exec_prefix}/lib 29 | includedir=${prefix}/include 30 | supported_protocols="HTTP HTTPS" 31 | supported_features="SSL libz IDN NTLM" 32 | 33 | Name: libcurl 34 | URL: http://curl.haxx.se/ 35 | Description: Library to transfer files with ftp, http, etc. 36 | Version: 7.21.4 37 | Libs: -L${libdir} -lcurl -lssl -lcrypto 38 | Libs.private: -lidn -lssl -lcrypto -lrt -lssl -lcrypto -lz -lssl -lcrypto 39 | Cflags: -I${includedir} 40 | -------------------------------------------------------------------------------- /lib/jsmn/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Serge A. Zaitsev 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /lib/jsmn/Makefile: -------------------------------------------------------------------------------- 1 | # You can put your build options here 2 | -include config.mk 3 | 4 | all: libjsmn.a 5 | 6 | libjsmn.a: jsmn.o 7 | $(AR) rc $@ $^ 8 | 9 | %.o: %.c jsmn.h 10 | $(CC) -c $(CFLAGS) $< -o $@ 11 | 12 | test: test_default test_strict test_links test_strict_links 13 | test_default: test/tests.c 14 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o test/$@ 15 | ./test/$@ 16 | test_strict: test/tests.c 17 | $(CC) -DJSMN_STRICT=1 $(CFLAGS) $(LDFLAGS) $< -o test/$@ 18 | ./test/$@ 19 | test_links: test/tests.c 20 | $(CC) -DJSMN_PARENT_LINKS=1 $(CFLAGS) $(LDFLAGS) $< -o test/$@ 21 | ./test/$@ 22 | test_strict_links: test/tests.c 23 | $(CC) -DJSMN_STRICT=1 -DJSMN_PARENT_LINKS=1 $(CFLAGS) $(LDFLAGS) $< -o test/$@ 24 | ./test/$@ 25 | 26 | jsmn_test.o: jsmn_test.c libjsmn.a 27 | 28 | simple_example: example/simple.o libjsmn.a 29 | $(CC) $(LDFLAGS) $^ -o $@ 30 | 31 | jsondump: example/jsondump.o libjsmn.a 32 | $(CC) $(LDFLAGS) $^ -o $@ 33 | 34 | clean: 35 | rm -f *.o example/*.o 36 | rm -f *.a *.so 37 | rm -f simple_example 38 | rm -f jsondump 39 | 40 | .PHONY: all clean test 41 | 42 | -------------------------------------------------------------------------------- /lib/jsmn/README.md: -------------------------------------------------------------------------------- 1 | JSMN 2 | ==== 3 | 4 | [![Build Status](https://travis-ci.org/zserge/jsmn.svg?branch=master)](https://travis-ci.org/zserge/jsmn) 5 | 6 | jsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C. It can be 7 | easily integrated into resource-limited or embedded projects. 8 | 9 | You can find more information about JSON format at [json.org][1] 10 | 11 | Library sources are available at https://github.com/zserge/jsmn 12 | 13 | The web page with some information about jsmn can be found at 14 | [http://zserge.com/jsmn.html][2] 15 | 16 | Philosophy 17 | ---------- 18 | 19 | Most JSON parsers offer you a bunch of functions to load JSON data, parse it 20 | and extract any value by its name. jsmn proves that checking the correctness of 21 | every JSON packet or allocating temporary objects to store parsed JSON fields 22 | often is an overkill. 23 | 24 | JSON format itself is extremely simple, so why should we complicate it? 25 | 26 | jsmn is designed to be **robust** (it should work fine even with erroneous 27 | data), **fast** (it should parse data on the fly), **portable** (no superfluous 28 | dependencies or non-standard C extensions). And of course, **simplicity** is a 29 | key feature - simple code style, simple algorithm, simple integration into 30 | other projects. 31 | 32 | Features 33 | -------- 34 | 35 | * compatible with C89 36 | * no dependencies (even libc!) 37 | * highly portable (tested on x86/amd64, ARM, AVR) 38 | * about 200 lines of code 39 | * extremely small code footprint 40 | * API contains only 2 functions 41 | * no dynamic memory allocation 42 | * incremental single-pass parsing 43 | * library code is covered with unit-tests 44 | 45 | Design 46 | ------ 47 | 48 | The rudimentary jsmn object is a **token**. Let's consider a JSON string: 49 | 50 | '{ "name" : "Jack", "age" : 27 }' 51 | 52 | It holds the following tokens: 53 | 54 | * Object: `{ "name" : "Jack", "age" : 27}` (the whole object) 55 | * Strings: `"name"`, `"Jack"`, `"age"` (keys and some values) 56 | * Number: `27` 57 | 58 | In jsmn, tokens do not hold any data, but point to token boundaries in JSON 59 | string instead. In the example above jsmn will create tokens like: Object 60 | [0..31], String [3..7], String [12..16], String [20..23], Number [27..29]. 61 | 62 | Every jsmn token has a type, which indicates the type of corresponding JSON 63 | token. jsmn supports the following token types: 64 | 65 | * Object - a container of key-value pairs, e.g.: 66 | `{ "foo":"bar", "x":0.3 }` 67 | * Array - a sequence of values, e.g.: 68 | `[ 1, 2, 3 ]` 69 | * String - a quoted sequence of chars, e.g.: `"foo"` 70 | * Primitive - a number, a boolean (`true`, `false`) or `null` 71 | 72 | Besides start/end positions, jsmn tokens for complex types (like arrays 73 | or objects) also contain a number of child items, so you can easily follow 74 | object hierarchy. 75 | 76 | This approach provides enough information for parsing any JSON data and makes 77 | it possible to use zero-copy techniques. 78 | 79 | Install 80 | ------- 81 | 82 | To clone the repository you should have Git installed. Just run: 83 | 84 | $ git clone https://github.com/zserge/jsmn 85 | 86 | Repository layout is simple: jsmn.c and jsmn.h are library files, tests are in 87 | the jsmn\_test.c, you will also find README, LICENSE and Makefile files inside. 88 | 89 | To build the library, run `make`. It is also recommended to run `make test`. 90 | Let me know, if some tests fail. 91 | 92 | If build was successful, you should get a `libjsmn.a` library. 93 | The header file you should include is called `"jsmn.h"`. 94 | 95 | API 96 | --- 97 | 98 | Token types are described by `jsmntype_t`: 99 | 100 | typedef enum { 101 | JSMN_UNDEFINED = 0, 102 | JSMN_OBJECT = 1, 103 | JSMN_ARRAY = 2, 104 | JSMN_STRING = 3, 105 | JSMN_PRIMITIVE = 4 106 | } jsmntype_t; 107 | 108 | **Note:** Unlike JSON data types, primitive tokens are not divided into 109 | numbers, booleans and null, because one can easily tell the type using the 110 | first character: 111 | 112 | * 't', 'f' - boolean 113 | * 'n' - null 114 | * '-', '0'..'9' - number 115 | 116 | Token is an object of `jsmntok_t` type: 117 | 118 | typedef struct { 119 | jsmntype_t type; // Token type 120 | int start; // Token start position 121 | int end; // Token end position 122 | int size; // Number of child (nested) tokens 123 | } jsmntok_t; 124 | 125 | **Note:** string tokens point to the first character after 126 | the opening quote and the previous symbol before final quote. This was made 127 | to simplify string extraction from JSON data. 128 | 129 | All job is done by `jsmn_parser` object. You can initialize a new parser using: 130 | 131 | jsmn_parser parser; 132 | jsmntok_t tokens[10]; 133 | 134 | jsmn_init(&parser); 135 | 136 | // js - pointer to JSON string 137 | // tokens - an array of tokens available 138 | // 10 - number of tokens available 139 | jsmn_parse(&parser, js, strlen(js), tokens, 10); 140 | 141 | This will create a parser, and then it tries to parse up to 10 JSON tokens from 142 | the `js` string. 143 | 144 | A non-negative return value of `jsmn_parse` is the number of tokens actually 145 | used by the parser. 146 | Passing NULL instead of the tokens array would not store parsing results, but 147 | instead the function will return the value of tokens needed to parse the given 148 | string. This can be useful if you don't know yet how many tokens to allocate. 149 | 150 | If something goes wrong, you will get an error. Error will be one of these: 151 | 152 | * `JSMN_ERROR_INVAL` - bad token, JSON string is corrupted 153 | * `JSMN_ERROR_NOMEM` - not enough tokens, JSON string is too large 154 | * `JSMN_ERROR_PART` - JSON string is too short, expecting more JSON data 155 | 156 | If you get `JSON_ERROR_NOMEM`, you can re-allocate more tokens and call 157 | `jsmn_parse` once more. If you read json data from the stream, you can 158 | periodically call `jsmn_parse` and check if return value is `JSON_ERROR_PART`. 159 | You will get this error until you reach the end of JSON data. 160 | 161 | Other info 162 | ---------- 163 | 164 | This software is distributed under [MIT license](http://www.opensource.org/licenses/mit-license.php), 165 | so feel free to integrate it in your commercial products. 166 | 167 | [1]: http://www.json.org/ 168 | [2]: http://zserge.com/jsmn.html 169 | -------------------------------------------------------------------------------- /lib/jsmn/example/jsondump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../jsmn.h" 7 | 8 | /* Function realloc_it() is a wrapper function for standart realloc() 9 | * with one difference - it frees old memory pointer in case of realloc 10 | * failure. Thus, DO NOT use old data pointer in anyway after call to 11 | * realloc_it(). If your code has some kind of fallback algorithm if 12 | * memory can't be re-allocated - use standart realloc() instead. 13 | */ 14 | static inline void *realloc_it(void *ptrmem, size_t size) { 15 | void *p = realloc(ptrmem, size); 16 | if (!p) { 17 | free (ptrmem); 18 | fprintf(stderr, "realloc(): errno=%d\n", errno); 19 | } 20 | return p; 21 | } 22 | 23 | /* 24 | * An example of reading JSON from stdin and printing its content to stdout. 25 | * The output looks like YAML, but I'm not sure if it's really compatible. 26 | */ 27 | 28 | static int dump(const char *js, jsmntok_t *t, size_t count, int indent) { 29 | int i, j, k; 30 | if (count == 0) { 31 | return 0; 32 | } 33 | if (t->type == JSMN_PRIMITIVE) { 34 | printf("%.*s", t->end - t->start, js+t->start); 35 | return 1; 36 | } else if (t->type == JSMN_STRING) { 37 | printf("'%.*s'", t->end - t->start, js+t->start); 38 | return 1; 39 | } else if (t->type == JSMN_OBJECT) { 40 | printf("\n"); 41 | j = 0; 42 | for (i = 0; i < t->size; i++) { 43 | for (k = 0; k < indent; k++) printf(" "); 44 | j += dump(js, t+1+j, count-j, indent+1); 45 | printf(": "); 46 | j += dump(js, t+1+j, count-j, indent+1); 47 | printf("\n"); 48 | } 49 | return j+1; 50 | } else if (t->type == JSMN_ARRAY) { 51 | j = 0; 52 | printf("\n"); 53 | for (i = 0; i < t->size; i++) { 54 | for (k = 0; k < indent-1; k++) printf(" "); 55 | printf(" - "); 56 | j += dump(js, t+1+j, count-j, indent+1); 57 | printf("\n"); 58 | } 59 | return j+1; 60 | } 61 | return 0; 62 | } 63 | 64 | int main() { 65 | int r; 66 | int eof_expected = 0; 67 | char *js = NULL; 68 | size_t jslen = 0; 69 | char buf[BUFSIZ]; 70 | 71 | jsmn_parser p; 72 | jsmntok_t *tok; 73 | size_t tokcount = 2; 74 | 75 | /* Prepare parser */ 76 | jsmn_init(&p); 77 | 78 | /* Allocate some tokens as a start */ 79 | tok = malloc(sizeof(*tok) * tokcount); 80 | if (tok == NULL) { 81 | fprintf(stderr, "malloc(): errno=%d\n", errno); 82 | return 3; 83 | } 84 | 85 | for (;;) { 86 | /* Read another chunk */ 87 | r = fread(buf, 1, sizeof(buf), stdin); 88 | if (r < 0) { 89 | fprintf(stderr, "fread(): %d, errno=%d\n", r, errno); 90 | return 1; 91 | } 92 | if (r == 0) { 93 | if (eof_expected != 0) { 94 | return 0; 95 | } else { 96 | fprintf(stderr, "fread(): unexpected EOF\n"); 97 | return 2; 98 | } 99 | } 100 | 101 | js = realloc_it(js, jslen + r + 1); 102 | if (js == NULL) { 103 | return 3; 104 | } 105 | strncpy(js + jslen, buf, r); 106 | jslen = jslen + r; 107 | 108 | again: 109 | r = jsmn_parse(&p, js, jslen, tok, tokcount); 110 | if (r < 0) { 111 | if (r == JSMN_ERROR_NOMEM) { 112 | tokcount = tokcount * 2; 113 | tok = realloc_it(tok, sizeof(*tok) * tokcount); 114 | if (tok == NULL) { 115 | return 3; 116 | } 117 | goto again; 118 | } 119 | } else { 120 | dump(js, tok, p.toknext, 0); 121 | eof_expected = 1; 122 | } 123 | } 124 | 125 | return EXIT_SUCCESS; 126 | } 127 | -------------------------------------------------------------------------------- /lib/jsmn/example/simple.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../jsmn.h" 5 | 6 | /* 7 | * A small example of jsmn parsing when JSON structure is known and number of 8 | * tokens is predictable. 9 | */ 10 | 11 | static const char *JSON_STRING = 12 | "{\"user\": \"johndoe\", \"admin\": false, \"uid\": 1000,\n " 13 | "\"groups\": [\"users\", \"wheel\", \"audio\", \"video\"]}"; 14 | 15 | static int jsoneq(const char *json, jsmntok_t *tok, const char *s) { 16 | if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start && 17 | strncmp(json + tok->start, s, tok->end - tok->start) == 0) { 18 | return 0; 19 | } 20 | return -1; 21 | } 22 | 23 | int main() { 24 | int i; 25 | int r; 26 | jsmn_parser p; 27 | jsmntok_t t[128]; /* We expect no more than 128 tokens */ 28 | 29 | jsmn_init(&p); 30 | r = jsmn_parse(&p, JSON_STRING, strlen(JSON_STRING), t, sizeof(t)/sizeof(t[0])); 31 | if (r < 0) { 32 | printf("Failed to parse JSON: %d\n", r); 33 | return 1; 34 | } 35 | 36 | /* Assume the top-level element is an object */ 37 | if (r < 1 || t[0].type != JSMN_OBJECT) { 38 | printf("Object expected\n"); 39 | return 1; 40 | } 41 | 42 | /* Loop over all keys of the root object */ 43 | for (i = 1; i < r; i++) { 44 | if (jsoneq(JSON_STRING, &t[i], "user") == 0) { 45 | /* We may use strndup() to fetch string value */ 46 | printf("- User: %.*s\n", t[i+1].end-t[i+1].start, 47 | JSON_STRING + t[i+1].start); 48 | i++; 49 | } else if (jsoneq(JSON_STRING, &t[i], "admin") == 0) { 50 | /* We may additionally check if the value is either "true" or "false" */ 51 | printf("- Admin: %.*s\n", t[i+1].end-t[i+1].start, 52 | JSON_STRING + t[i+1].start); 53 | i++; 54 | } else if (jsoneq(JSON_STRING, &t[i], "uid") == 0) { 55 | /* We may want to do strtol() here to get numeric value */ 56 | printf("- UID: %.*s\n", t[i+1].end-t[i+1].start, 57 | JSON_STRING + t[i+1].start); 58 | i++; 59 | } else if (jsoneq(JSON_STRING, &t[i], "groups") == 0) { 60 | int j; 61 | printf("- Groups:\n"); 62 | if (t[i+1].type != JSMN_ARRAY) { 63 | continue; /* We expect groups to be an array of strings */ 64 | } 65 | for (j = 0; j < t[i+1].size; j++) { 66 | jsmntok_t *g = &t[i+j+2]; 67 | printf(" * %.*s\n", g->end - g->start, JSON_STRING + g->start); 68 | } 69 | i += t[i+1].size + 1; 70 | } else { 71 | printf("Unexpected key: %.*s\n", t[i].end-t[i].start, 72 | JSON_STRING + t[i].start); 73 | } 74 | } 75 | return EXIT_SUCCESS; 76 | } 77 | -------------------------------------------------------------------------------- /lib/jsmn/jsmn.c: -------------------------------------------------------------------------------- 1 | #include "jsmn.h" 2 | 3 | /** 4 | * Allocates a fresh unused token from the token pull. 5 | */ 6 | static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, 7 | jsmntok_t *tokens, size_t num_tokens) { 8 | jsmntok_t *tok; 9 | if (parser->toknext >= num_tokens) { 10 | return NULL; 11 | } 12 | tok = &tokens[parser->toknext++]; 13 | tok->start = tok->end = -1; 14 | tok->size = 0; 15 | #ifdef JSMN_PARENT_LINKS 16 | tok->parent = -1; 17 | #endif 18 | return tok; 19 | } 20 | 21 | /** 22 | * Fills token type and boundaries. 23 | */ 24 | static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, 25 | int start, int end) { 26 | token->type = type; 27 | token->start = start; 28 | token->end = end; 29 | token->size = 0; 30 | } 31 | 32 | /** 33 | * Fills next available token with JSON primitive. 34 | */ 35 | static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, 36 | size_t len, jsmntok_t *tokens, size_t num_tokens) { 37 | jsmntok_t *token; 38 | int start; 39 | 40 | start = parser->pos; 41 | 42 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 43 | switch (js[parser->pos]) { 44 | #ifndef JSMN_STRICT 45 | /* In strict mode primitive must be followed by "," or "}" or "]" */ 46 | case ':': 47 | #endif 48 | case '\t' : case '\r' : case '\n' : case ' ' : 49 | case ',' : case ']' : case '}' : 50 | goto found; 51 | default: // do nothing; 52 | break; 53 | } 54 | if (js[parser->pos] < 32 || js[parser->pos] >= 127) { 55 | parser->pos = start; 56 | return JSMN_ERROR_INVAL; 57 | } 58 | } 59 | #ifdef JSMN_STRICT 60 | /* In strict mode primitive must be followed by a comma/object/array */ 61 | parser->pos = start; 62 | return JSMN_ERROR_PART; 63 | #endif 64 | 65 | found: 66 | if (tokens == NULL) { 67 | parser->pos--; 68 | return 0; 69 | } 70 | token = jsmn_alloc_token(parser, tokens, num_tokens); 71 | if (token == NULL) { 72 | parser->pos = start; 73 | return JSMN_ERROR_NOMEM; 74 | } 75 | jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); 76 | #ifdef JSMN_PARENT_LINKS 77 | token->parent = parser->toksuper; 78 | #endif 79 | parser->pos--; 80 | return 0; 81 | } 82 | 83 | /** 84 | * Fills next token with JSON string. 85 | */ 86 | static int jsmn_parse_string(jsmn_parser *parser, const char *js, 87 | size_t len, jsmntok_t *tokens, size_t num_tokens) { 88 | jsmntok_t *token; 89 | 90 | int start = parser->pos; 91 | 92 | parser->pos++; 93 | 94 | /* Skip starting quote */ 95 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 96 | char c = js[parser->pos]; 97 | 98 | /* Quote: end of string */ 99 | if (c == '\"') { 100 | if (tokens == NULL) { 101 | return 0; 102 | } 103 | token = jsmn_alloc_token(parser, tokens, num_tokens); 104 | if (token == NULL) { 105 | parser->pos = start; 106 | return JSMN_ERROR_NOMEM; 107 | } 108 | jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); 109 | #ifdef JSMN_PARENT_LINKS 110 | token->parent = parser->toksuper; 111 | #endif 112 | return 0; 113 | } 114 | 115 | /* Backslash: Quoted symbol expected */ 116 | if (c == '\\' && parser->pos + 1 < len) { 117 | int i; 118 | parser->pos++; 119 | switch (js[parser->pos]) { 120 | /* Allowed escaped symbols */ 121 | case '\"': case '/' : case '\\' : case 'b' : 122 | case 'f' : case 'r' : case 'n' : case 't' : 123 | break; 124 | /* Allows escaped symbol \uXXXX */ 125 | case 'u': 126 | parser->pos++; 127 | for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) { 128 | /* If it isn't a hex character we have an error */ 129 | if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ 130 | (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ 131 | (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ 132 | parser->pos = start; 133 | return JSMN_ERROR_INVAL; 134 | } 135 | parser->pos++; 136 | } 137 | parser->pos--; 138 | break; 139 | /* Unexpected symbol */ 140 | default: 141 | parser->pos = start; 142 | return JSMN_ERROR_INVAL; 143 | } 144 | } 145 | } 146 | parser->pos = start; 147 | return JSMN_ERROR_PART; 148 | } 149 | 150 | /** 151 | * Parse JSON string and fill tokens. 152 | */ 153 | int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, 154 | jsmntok_t *tokens, unsigned int num_tokens) { 155 | int r; 156 | int i; 157 | jsmntok_t *token; 158 | int count = parser->toknext; 159 | 160 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 161 | char c; 162 | jsmntype_t type; 163 | 164 | c = js[parser->pos]; 165 | switch (c) { 166 | case '{': case '[': 167 | count++; 168 | if (tokens == NULL) { 169 | break; 170 | } 171 | token = jsmn_alloc_token(parser, tokens, num_tokens); 172 | if (token == NULL) 173 | return JSMN_ERROR_NOMEM; 174 | if (parser->toksuper != -1) { 175 | tokens[parser->toksuper].size++; 176 | #ifdef JSMN_PARENT_LINKS 177 | token->parent = parser->toksuper; 178 | #endif 179 | } 180 | token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); 181 | token->start = parser->pos; 182 | parser->toksuper = parser->toknext - 1; 183 | break; 184 | case '}': case ']': 185 | if (tokens == NULL) 186 | break; 187 | type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); 188 | #ifdef JSMN_PARENT_LINKS 189 | if (parser->toknext < 1) { 190 | return JSMN_ERROR_INVAL; 191 | } 192 | token = &tokens[parser->toknext - 1]; 193 | for (;;) { 194 | if (token->start != -1 && token->end == -1) { 195 | if (token->type != type) { 196 | return JSMN_ERROR_INVAL; 197 | } 198 | token->end = parser->pos + 1; 199 | parser->toksuper = token->parent; 200 | break; 201 | } 202 | if (token->parent == -1) { 203 | if(token->type != type || parser->toksuper == -1) { 204 | return JSMN_ERROR_INVAL; 205 | } 206 | break; 207 | } 208 | token = &tokens[token->parent]; 209 | } 210 | #else 211 | for (i = parser->toknext - 1; i >= 0; i--) { 212 | token = &tokens[i]; 213 | if (token->start != -1 && token->end == -1) { 214 | if (token->type != type) { 215 | return JSMN_ERROR_INVAL; 216 | } 217 | parser->toksuper = -1; 218 | token->end = parser->pos + 1; 219 | break; 220 | } 221 | } 222 | /* Error if unmatched closing bracket */ 223 | if (i == -1) return JSMN_ERROR_INVAL; 224 | for (; i >= 0; i--) { 225 | token = &tokens[i]; 226 | if (token->start != -1 && token->end == -1) { 227 | parser->toksuper = i; 228 | break; 229 | } 230 | } 231 | #endif 232 | break; 233 | case '\"': 234 | r = jsmn_parse_string(parser, js, len, tokens, num_tokens); 235 | if (r < 0) return r; 236 | count++; 237 | if (parser->toksuper != -1 && tokens != NULL) 238 | tokens[parser->toksuper].size++; 239 | break; 240 | case '\t' : case '\r' : case '\n' : case ' ': 241 | break; 242 | case ':': 243 | parser->toksuper = parser->toknext - 1; 244 | break; 245 | case ',': 246 | if (tokens != NULL && parser->toksuper != -1 && 247 | tokens[parser->toksuper].type != JSMN_ARRAY && 248 | tokens[parser->toksuper].type != JSMN_OBJECT) { 249 | #ifdef JSMN_PARENT_LINKS 250 | parser->toksuper = tokens[parser->toksuper].parent; 251 | #else 252 | for (i = parser->toknext - 1; i >= 0; i--) { 253 | if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { 254 | if (tokens[i].start != -1 && tokens[i].end == -1) { 255 | parser->toksuper = i; 256 | break; 257 | } 258 | } 259 | } 260 | #endif 261 | } 262 | break; 263 | #ifdef JSMN_STRICT 264 | /* In strict mode primitives are: numbers and booleans */ 265 | case '-': case '0': case '1' : case '2': case '3' : case '4': 266 | case '5': case '6': case '7' : case '8': case '9': 267 | case 't': case 'f': case 'n' : 268 | /* And they must not be keys of the object */ 269 | if (tokens != NULL && parser->toksuper != -1) { 270 | jsmntok_t *t = &tokens[parser->toksuper]; 271 | if (t->type == JSMN_OBJECT || 272 | (t->type == JSMN_STRING && t->size != 0)) { 273 | return JSMN_ERROR_INVAL; 274 | } 275 | } 276 | #else 277 | /* In non-strict mode every unquoted value is a primitive */ 278 | default: 279 | #endif 280 | r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); 281 | if (r < 0) return r; 282 | count++; 283 | if (parser->toksuper != -1 && tokens != NULL) 284 | tokens[parser->toksuper].size++; 285 | break; 286 | 287 | #ifdef JSMN_STRICT 288 | /* Unexpected char in strict mode */ 289 | default: 290 | return JSMN_ERROR_INVAL; 291 | #endif 292 | } 293 | } 294 | 295 | if (tokens != NULL) { 296 | for (i = parser->toknext - 1; i >= 0; i--) { 297 | /* Unmatched opened object or array */ 298 | if (tokens[i].start != -1 && tokens[i].end == -1) { 299 | return JSMN_ERROR_PART; 300 | } 301 | } 302 | } 303 | 304 | return count; 305 | } 306 | 307 | /** 308 | * Creates a new parser based over a given buffer with an array of tokens 309 | * available. 310 | */ 311 | void jsmn_init(jsmn_parser *parser) { 312 | parser->pos = 0; 313 | parser->toknext = 0; 314 | parser->toksuper = -1; 315 | } 316 | 317 | -------------------------------------------------------------------------------- /lib/jsmn/jsmn.h: -------------------------------------------------------------------------------- 1 | #ifndef __JSMN_H_ 2 | #define __JSMN_H_ 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /** 11 | * JSON type identifier. Basic types are: 12 | * o Object 13 | * o Array 14 | * o String 15 | * o Other primitive: number, boolean (true/false) or null 16 | */ 17 | typedef enum { 18 | JSMN_UNDEFINED = 0, 19 | JSMN_OBJECT = 1, 20 | JSMN_ARRAY = 2, 21 | JSMN_STRING = 3, 22 | JSMN_PRIMITIVE = 4 23 | } jsmntype_t; 24 | 25 | enum jsmnerr { 26 | /* Not enough tokens were provided */ 27 | JSMN_ERROR_NOMEM = -1, 28 | /* Invalid character inside JSON string */ 29 | JSMN_ERROR_INVAL = -2, 30 | /* The string is not a full JSON packet, more bytes expected */ 31 | JSMN_ERROR_PART = -3 32 | }; 33 | 34 | /** 35 | * JSON token description. 36 | * type type (object, array, string etc.) 37 | * start start position in JSON data string 38 | * end end position in JSON data string 39 | */ 40 | typedef struct { 41 | jsmntype_t type; 42 | int start; 43 | int end; 44 | int size; 45 | #ifdef JSMN_PARENT_LINKS 46 | int parent; 47 | #endif 48 | } jsmntok_t; 49 | 50 | /** 51 | * JSON parser. Contains an array of token blocks available. Also stores 52 | * the string being parsed now and current position in that string 53 | */ 54 | typedef struct { 55 | unsigned int pos; /* offset in the JSON string */ 56 | unsigned int toknext; /* next token to allocate */ 57 | int toksuper; /* superior token node, e.g parent object or array */ 58 | } jsmn_parser; 59 | 60 | /** 61 | * Create JSON parser over an array of tokens 62 | */ 63 | void jsmn_init(jsmn_parser *parser); 64 | 65 | /** 66 | * Run JSON parser. It parses a JSON data string into and array of tokens, each describing 67 | * a single JSON object. 68 | */ 69 | int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, 70 | jsmntok_t *tokens, unsigned int num_tokens); 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif 75 | 76 | #endif /* __JSMN_H_ */ 77 | -------------------------------------------------------------------------------- /lib/jsmn/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsmn", 3 | "keywords": "json", 4 | "description": "Minimalistic JSON parser/tokenizer in C. It can be easily integrated into resource-limited or embedded projects", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/zserge/jsmn.git" 9 | }, 10 | "frameworks": "*", 11 | "platforms": "*", 12 | "examples": [ 13 | "example/*.c" 14 | ], 15 | "exclude": "test" 16 | } 17 | -------------------------------------------------------------------------------- /lib/jsmn/simple_example: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cekage/wallindle/1ffef0033b764e459e4dea0a5defb3f2776c9165/lib/jsmn/simple_example -------------------------------------------------------------------------------- /lib/jsmn/test/test.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEST_H__ 2 | #define __TEST_H__ 3 | 4 | static int test_passed = 0; 5 | static int test_failed = 0; 6 | 7 | /* Terminate current test with error */ 8 | #define fail() return __LINE__ 9 | 10 | /* Successful end of the test case */ 11 | #define done() return 0 12 | 13 | /* Check single condition */ 14 | #define check(cond) do { if (!(cond)) fail(); } while (0) 15 | 16 | /* Test runner */ 17 | static void test(int (*func)(void), const char *name) { 18 | int r = func(); 19 | if (r == 0) { 20 | test_passed++; 21 | } else { 22 | test_failed++; 23 | printf("FAILED: %s (at line %d)\n", name, r); 24 | } 25 | } 26 | 27 | #endif /* __TEST_H__ */ 28 | -------------------------------------------------------------------------------- /lib/jsmn/test/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "test.h" 7 | #include "testutil.h" 8 | 9 | int test_empty(void) { 10 | check(parse("{}", 1, 1, 11 | JSMN_OBJECT, 0, 2, 0)); 12 | check(parse("[]", 1, 1, 13 | JSMN_ARRAY, 0, 2, 0)); 14 | check(parse("[{},{}]", 3, 3, 15 | JSMN_ARRAY, 0, 7, 2, 16 | JSMN_OBJECT, 1, 3, 0, 17 | JSMN_OBJECT, 4, 6, 0)); 18 | return 0; 19 | } 20 | 21 | int test_object(void) { 22 | check(parse("{\"a\":0}", 3, 3, 23 | JSMN_OBJECT, 0, 7, 1, 24 | JSMN_STRING, "a", 1, 25 | JSMN_PRIMITIVE, "0")); 26 | check(parse("{\"a\":[]}", 3, 3, 27 | JSMN_OBJECT, 0, 8, 1, 28 | JSMN_STRING, "a", 1, 29 | JSMN_ARRAY, 5, 7, 0)); 30 | check(parse("{\"a\":{},\"b\":{}}", 5, 5, 31 | JSMN_OBJECT, -1, -1, 2, 32 | JSMN_STRING, "a", 1, 33 | JSMN_OBJECT, -1, -1, 0, 34 | JSMN_STRING, "b", 1, 35 | JSMN_OBJECT, -1, -1, 0)); 36 | check(parse("{\n \"Day\": 26,\n \"Month\": 9,\n \"Year\": 12\n }", 7, 7, 37 | JSMN_OBJECT, -1, -1, 3, 38 | JSMN_STRING, "Day", 1, 39 | JSMN_PRIMITIVE, "26", 40 | JSMN_STRING, "Month", 1, 41 | JSMN_PRIMITIVE, "9", 42 | JSMN_STRING, "Year", 1, 43 | JSMN_PRIMITIVE, "12")); 44 | check(parse("{\"a\": 0, \"b\": \"c\"}", 5, 5, 45 | JSMN_OBJECT, -1, -1, 2, 46 | JSMN_STRING, "a", 1, 47 | JSMN_PRIMITIVE, "0", 48 | JSMN_STRING, "b", 1, 49 | JSMN_STRING, "c", 0)); 50 | 51 | #ifdef JSMN_STRICT 52 | check(parse("{\"a\"\n0}", JSMN_ERROR_INVAL, 3)); 53 | check(parse("{\"a\", 0}", JSMN_ERROR_INVAL, 3)); 54 | check(parse("{\"a\": {2}}", JSMN_ERROR_INVAL, 3)); 55 | check(parse("{\"a\": {2: 3}}", JSMN_ERROR_INVAL, 3)); 56 | check(parse("{\"a\": {\"a\": 2 3}}", JSMN_ERROR_INVAL, 5)); 57 | /* FIXME */ 58 | /*check(parse("{\"a\"}", JSMN_ERROR_INVAL, 2));*/ 59 | /*check(parse("{\"a\": 1, \"b\"}", JSMN_ERROR_INVAL, 4));*/ 60 | /*check(parse("{\"a\",\"b\":1}", JSMN_ERROR_INVAL, 4));*/ 61 | /*check(parse("{\"a\":1,}", JSMN_ERROR_INVAL, 4));*/ 62 | /*check(parse("{\"a\":\"b\":\"c\"}", JSMN_ERROR_INVAL, 4));*/ 63 | /*check(parse("{,}", JSMN_ERROR_INVAL, 4));*/ 64 | #endif 65 | return 0; 66 | } 67 | 68 | int test_array(void) { 69 | /* FIXME */ 70 | /*check(parse("[10}", JSMN_ERROR_INVAL, 3));*/ 71 | /*check(parse("[1,,3]", JSMN_ERROR_INVAL, 3)*/ 72 | check(parse("[10]", 2, 2, 73 | JSMN_ARRAY, -1, -1, 1, 74 | JSMN_PRIMITIVE, "10")); 75 | check(parse("{\"a\": 1]", JSMN_ERROR_INVAL, 3)); 76 | /* FIXME */ 77 | /*check(parse("[\"a\": 1]", JSMN_ERROR_INVAL, 3));*/ 78 | return 0; 79 | } 80 | 81 | int test_primitive(void) { 82 | check(parse("{\"boolVar\" : true }", 3, 3, 83 | JSMN_OBJECT, -1, -1, 1, 84 | JSMN_STRING, "boolVar", 1, 85 | JSMN_PRIMITIVE, "true")); 86 | check(parse("{\"boolVar\" : false }", 3, 3, 87 | JSMN_OBJECT, -1, -1, 1, 88 | JSMN_STRING, "boolVar", 1, 89 | JSMN_PRIMITIVE, "false")); 90 | check(parse("{\"nullVar\" : null }", 3, 3, 91 | JSMN_OBJECT, -1, -1, 1, 92 | JSMN_STRING, "nullVar", 1, 93 | JSMN_PRIMITIVE, "null")); 94 | check(parse("{\"intVar\" : 12}", 3, 3, 95 | JSMN_OBJECT, -1, -1, 1, 96 | JSMN_STRING, "intVar", 1, 97 | JSMN_PRIMITIVE, "12")); 98 | check(parse("{\"floatVar\" : 12.345}", 3, 3, 99 | JSMN_OBJECT, -1, -1, 1, 100 | JSMN_STRING, "floatVar", 1, 101 | JSMN_PRIMITIVE, "12.345")); 102 | return 0; 103 | } 104 | 105 | int test_string(void) { 106 | check(parse("{\"strVar\" : \"hello world\"}", 3, 3, 107 | JSMN_OBJECT, -1, -1, 1, 108 | JSMN_STRING, "strVar", 1, 109 | JSMN_STRING, "hello world", 0)); 110 | check(parse("{\"strVar\" : \"escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\\"}", 3, 3, 111 | JSMN_OBJECT, -1, -1, 1, 112 | JSMN_STRING, "strVar", 1, 113 | JSMN_STRING, "escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\", 0)); 114 | check(parse("{\"strVar\": \"\"}", 3, 3, 115 | JSMN_OBJECT, -1, -1, 1, 116 | JSMN_STRING, "strVar", 1, 117 | JSMN_STRING, "", 0)); 118 | check(parse("{\"a\":\"\\uAbcD\"}", 3, 3, 119 | JSMN_OBJECT, -1, -1, 1, 120 | JSMN_STRING, "a", 1, 121 | JSMN_STRING, "\\uAbcD", 0)); 122 | check(parse("{\"a\":\"str\\u0000\"}", 3, 3, 123 | JSMN_OBJECT, -1, -1, 1, 124 | JSMN_STRING, "a", 1, 125 | JSMN_STRING, "str\\u0000", 0)); 126 | check(parse("{\"a\":\"\\uFFFFstr\"}", 3, 3, 127 | JSMN_OBJECT, -1, -1, 1, 128 | JSMN_STRING, "a", 1, 129 | JSMN_STRING, "\\uFFFFstr", 0)); 130 | check(parse("{\"a\":[\"\\u0280\"]}", 4, 4, 131 | JSMN_OBJECT, -1, -1, 1, 132 | JSMN_STRING, "a", 1, 133 | JSMN_ARRAY, -1, -1, 1, 134 | JSMN_STRING, "\\u0280", 0)); 135 | 136 | check(parse("{\"a\":\"str\\uFFGFstr\"}", JSMN_ERROR_INVAL, 3)); 137 | check(parse("{\"a\":\"str\\u@FfF\"}", JSMN_ERROR_INVAL, 3)); 138 | check(parse("{{\"a\":[\"\\u028\"]}", JSMN_ERROR_INVAL, 4)); 139 | return 0; 140 | } 141 | 142 | int test_partial_string(void) { 143 | int i; 144 | int r; 145 | jsmn_parser p; 146 | jsmntok_t tok[5]; 147 | const char *js = "{\"x\": \"va\\\\ue\", \"y\": \"value y\"}"; 148 | 149 | jsmn_init(&p); 150 | for (i = 1; i <= strlen(js); i++) { 151 | r = jsmn_parse(&p, js, i, tok, sizeof(tok)/sizeof(tok[0])); 152 | if (i == strlen(js)) { 153 | check(r == 5); 154 | check(tokeq(js, tok, 5, 155 | JSMN_OBJECT, -1, -1, 2, 156 | JSMN_STRING, "x", 1, 157 | JSMN_STRING, "va\\\\ue", 0, 158 | JSMN_STRING, "y", 1, 159 | JSMN_STRING, "value y", 0)); 160 | } else { 161 | check(r == JSMN_ERROR_PART); 162 | } 163 | } 164 | return 0; 165 | } 166 | 167 | int test_partial_array(void) { 168 | #ifdef JSMN_STRICT 169 | int r; 170 | int i; 171 | jsmn_parser p; 172 | jsmntok_t tok[10]; 173 | const char *js = "[ 1, true, [123, \"hello\"]]"; 174 | 175 | jsmn_init(&p); 176 | for (i = 1; i <= strlen(js); i++) { 177 | r = jsmn_parse(&p, js, i, tok, sizeof(tok)/sizeof(tok[0])); 178 | if (i == strlen(js)) { 179 | check(r == 6); 180 | check(tokeq(js, tok, 6, 181 | JSMN_ARRAY, -1, -1, 3, 182 | JSMN_PRIMITIVE, "1", 183 | JSMN_PRIMITIVE, "true", 184 | JSMN_ARRAY, -1, -1, 2, 185 | JSMN_PRIMITIVE, "123", 186 | JSMN_STRING, "hello", 0)); 187 | } else { 188 | check(r == JSMN_ERROR_PART); 189 | } 190 | } 191 | #endif 192 | return 0; 193 | } 194 | 195 | int test_array_nomem(void) { 196 | int i; 197 | int r; 198 | jsmn_parser p; 199 | jsmntok_t toksmall[10], toklarge[10]; 200 | const char *js; 201 | 202 | js = " [ 1, true, [123, \"hello\"]]"; 203 | 204 | for (i = 0; i < 6; i++) { 205 | jsmn_init(&p); 206 | memset(toksmall, 0, sizeof(toksmall)); 207 | memset(toklarge, 0, sizeof(toklarge)); 208 | r = jsmn_parse(&p, js, strlen(js), toksmall, i); 209 | check(r == JSMN_ERROR_NOMEM); 210 | 211 | memcpy(toklarge, toksmall, sizeof(toksmall)); 212 | 213 | r = jsmn_parse(&p, js, strlen(js), toklarge, 10); 214 | check(r >= 0); 215 | check(tokeq(js, toklarge, 4, 216 | JSMN_ARRAY, -1, -1, 3, 217 | JSMN_PRIMITIVE, "1", 218 | JSMN_PRIMITIVE, "true", 219 | JSMN_ARRAY, -1, -1, 2, 220 | JSMN_PRIMITIVE, "123", 221 | JSMN_STRING, "hello", 0)); 222 | } 223 | return 0; 224 | } 225 | 226 | int test_unquoted_keys(void) { 227 | #ifndef JSMN_STRICT 228 | int r; 229 | jsmn_parser p; 230 | jsmntok_t tok[10]; 231 | const char *js; 232 | 233 | jsmn_init(&p); 234 | js = "key1: \"value\"\nkey2 : 123"; 235 | 236 | r = jsmn_parse(&p, js, strlen(js), tok, 10); 237 | check(r >= 0); 238 | check(tokeq(js, tok, 4, 239 | JSMN_PRIMITIVE, "key1", 240 | JSMN_STRING, "value", 0, 241 | JSMN_PRIMITIVE, "key2", 242 | JSMN_PRIMITIVE, "123")); 243 | #endif 244 | return 0; 245 | } 246 | 247 | int test_issue_22(void) { 248 | int r; 249 | jsmn_parser p; 250 | jsmntok_t tokens[128]; 251 | const char *js; 252 | 253 | js = "{ \"height\":10, \"layers\":[ { \"data\":[6,6], \"height\":10, " 254 | "\"name\":\"Calque de Tile 1\", \"opacity\":1, \"type\":\"tilelayer\", " 255 | "\"visible\":true, \"width\":10, \"x\":0, \"y\":0 }], " 256 | "\"orientation\":\"orthogonal\", \"properties\": { }, \"tileheight\":32, " 257 | "\"tilesets\":[ { \"firstgid\":1, \"image\":\"..\\/images\\/tiles.png\", " 258 | "\"imageheight\":64, \"imagewidth\":160, \"margin\":0, \"name\":\"Tiles\", " 259 | "\"properties\":{}, \"spacing\":0, \"tileheight\":32, \"tilewidth\":32 }], " 260 | "\"tilewidth\":32, \"version\":1, \"width\":10 }"; 261 | jsmn_init(&p); 262 | r = jsmn_parse(&p, js, strlen(js), tokens, 128); 263 | check(r >= 0); 264 | return 0; 265 | } 266 | 267 | int test_issue_27(void) { 268 | const char *js = 269 | "{ \"name\" : \"Jack\", \"age\" : 27 } { \"name\" : \"Anna\", "; 270 | check(parse(js, JSMN_ERROR_PART, 8)); 271 | return 0; 272 | } 273 | 274 | int test_input_length(void) { 275 | const char *js; 276 | int r; 277 | jsmn_parser p; 278 | jsmntok_t tokens[10]; 279 | 280 | js = "{\"a\": 0}garbage"; 281 | 282 | jsmn_init(&p); 283 | r = jsmn_parse(&p, js, 8, tokens, 10); 284 | check(r == 3); 285 | check(tokeq(js, tokens, 3, 286 | JSMN_OBJECT, -1, -1, 1, 287 | JSMN_STRING, "a", 1, 288 | JSMN_PRIMITIVE, "0")); 289 | return 0; 290 | } 291 | 292 | int test_count(void) { 293 | jsmn_parser p; 294 | const char *js; 295 | 296 | js = "{}"; 297 | jsmn_init(&p); 298 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 1); 299 | 300 | js = "[]"; 301 | jsmn_init(&p); 302 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 1); 303 | 304 | js = "[[]]"; 305 | jsmn_init(&p); 306 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 2); 307 | 308 | js = "[[], []]"; 309 | jsmn_init(&p); 310 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 3); 311 | 312 | js = "[[], []]"; 313 | jsmn_init(&p); 314 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 3); 315 | 316 | js = "[[], [[]], [[], []]]"; 317 | jsmn_init(&p); 318 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 7); 319 | 320 | js = "[\"a\", [[], []]]"; 321 | jsmn_init(&p); 322 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 5); 323 | 324 | js = "[[], \"[], [[]]\", [[]]]"; 325 | jsmn_init(&p); 326 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 5); 327 | 328 | js = "[1, 2, 3]"; 329 | jsmn_init(&p); 330 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 4); 331 | 332 | js = "[1, 2, [3, \"a\"], null]"; 333 | jsmn_init(&p); 334 | check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 7); 335 | 336 | return 0; 337 | } 338 | 339 | 340 | int test_nonstrict(void) { 341 | #ifndef JSMN_STRICT 342 | const char *js; 343 | js = "a: 0garbage"; 344 | check(parse(js, 2, 2, 345 | JSMN_PRIMITIVE, "a", 346 | JSMN_PRIMITIVE, "0garbage")); 347 | 348 | js = "Day : 26\nMonth : Sep\n\nYear: 12"; 349 | check(parse(js, 6, 6, 350 | JSMN_PRIMITIVE, "Day", 351 | JSMN_PRIMITIVE, "26", 352 | JSMN_PRIMITIVE, "Month", 353 | JSMN_PRIMITIVE, "Sep", 354 | JSMN_PRIMITIVE, "Year", 355 | JSMN_PRIMITIVE, "12")); 356 | 357 | //nested {s don't cause a parse error. 358 | js = "\"key {1\": 1234"; 359 | check(parse(js, 2, 2, 360 | JSMN_STRING, "key {1", 1, 361 | JSMN_PRIMITIVE, "1234")); 362 | 363 | 364 | #endif 365 | return 0; 366 | } 367 | 368 | int test_unmatched_brackets(void) { 369 | const char *js; 370 | js = "\"key 1\": 1234}"; 371 | check(parse(js, JSMN_ERROR_INVAL, 2)); 372 | js = "{\"key 1\": 1234"; 373 | check(parse(js, JSMN_ERROR_PART, 3)); 374 | js = "{\"key 1\": 1234}}"; 375 | check(parse(js, JSMN_ERROR_INVAL, 3)); 376 | js = "\"key 1\"}: 1234"; 377 | check(parse(js, JSMN_ERROR_INVAL, 3)); 378 | js = "{\"key {1\": 1234}"; 379 | check(parse(js, 3, 3, 380 | JSMN_OBJECT, 0, 16, 1, 381 | JSMN_STRING, "key {1", 1, 382 | JSMN_PRIMITIVE, "1234")); 383 | js = "{{\"key 1\": 1234}"; 384 | check(parse(js, JSMN_ERROR_PART, 4)); 385 | return 0; 386 | } 387 | 388 | int main(void) { 389 | test(test_empty, "test for a empty JSON objects/arrays"); 390 | test(test_object, "test for a JSON objects"); 391 | test(test_array, "test for a JSON arrays"); 392 | test(test_primitive, "test primitive JSON data types"); 393 | test(test_string, "test string JSON data types"); 394 | 395 | test(test_partial_string, "test partial JSON string parsing"); 396 | test(test_partial_array, "test partial array reading"); 397 | test(test_array_nomem, "test array reading with a smaller number of tokens"); 398 | test(test_unquoted_keys, "test unquoted keys (like in JavaScript)"); 399 | test(test_input_length, "test strings that are not null-terminated"); 400 | test(test_issue_22, "test issue #22"); 401 | test(test_issue_27, "test issue #27"); 402 | test(test_count, "test tokens count estimation"); 403 | test(test_nonstrict, "test for non-strict mode"); 404 | test(test_unmatched_brackets, "test for unmatched brackets"); 405 | printf("\nPASSED: %d\nFAILED: %d\n", test_passed, test_failed); 406 | return (test_failed > 0); 407 | } 408 | -------------------------------------------------------------------------------- /lib/jsmn/test/testutil.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEST_UTIL_H__ 2 | #define __TEST_UTIL_H__ 3 | 4 | #include "../jsmn.c" 5 | 6 | static int vtokeq(const char *s, jsmntok_t *t, int numtok, va_list ap) { 7 | if (numtok > 0) { 8 | int i, start, end, size; 9 | int type; 10 | char *value; 11 | 12 | size = -1; 13 | value = NULL; 14 | for (i = 0; i < numtok; i++) { 15 | type = va_arg(ap, int); 16 | if (type == JSMN_STRING) { 17 | value = va_arg(ap, char *); 18 | size = va_arg(ap, int); 19 | start = end = -1; 20 | } else if (type == JSMN_PRIMITIVE) { 21 | value = va_arg(ap, char *); 22 | start = end = size = -1; 23 | } else { 24 | start = va_arg(ap, int); 25 | end = va_arg(ap, int); 26 | size = va_arg(ap, int); 27 | value = NULL; 28 | } 29 | if (t[i].type != type) { 30 | printf("token %d type is %d, not %d\n", i, t[i].type, type); 31 | return 0; 32 | } 33 | if (start != -1 && end != -1) { 34 | if (t[i].start != start) { 35 | printf("token %d start is %d, not %d\n", i, t[i].start, start); 36 | return 0; 37 | } 38 | if (t[i].end != end ) { 39 | printf("token %d end is %d, not %d\n", i, t[i].end, end); 40 | return 0; 41 | } 42 | } 43 | if (size != -1 && t[i].size != size) { 44 | printf("token %d size is %d, not %d\n", i, t[i].size, size); 45 | return 0; 46 | } 47 | 48 | if (s != NULL && value != NULL) { 49 | const char *p = s + t[i].start; 50 | if (strlen(value) != t[i].end - t[i].start || 51 | strncmp(p, value, t[i].end - t[i].start) != 0) { 52 | printf("token %d value is %.*s, not %s\n", i, t[i].end-t[i].start, 53 | s+t[i].start, value); 54 | return 0; 55 | } 56 | } 57 | } 58 | } 59 | return 1; 60 | } 61 | 62 | static int tokeq(const char *s, jsmntok_t *tokens, int numtok, ...) { 63 | int ok; 64 | va_list args; 65 | va_start(args, numtok); 66 | ok = vtokeq(s, tokens, numtok, args); 67 | va_end(args); 68 | return ok; 69 | } 70 | 71 | static int parse(const char *s, int status, int numtok, ...) { 72 | int r; 73 | int ok = 1; 74 | va_list args; 75 | jsmn_parser p; 76 | jsmntok_t *t = malloc(numtok * sizeof(jsmntok_t)); 77 | 78 | jsmn_init(&p); 79 | r = jsmn_parse(&p, s, strlen(s), t, numtok); 80 | if (r != status) { 81 | printf("status is %d, not %d\n", r, status); 82 | return 0; 83 | } 84 | 85 | if (status >= 0) { 86 | va_start(args, numtok); 87 | ok = vtokeq(s, t, numtok, args); 88 | va_end(args); 89 | } 90 | free(t); 91 | return ok; 92 | } 93 | 94 | #endif /* __TEST_UTIL_H__ */ 95 | -------------------------------------------------------------------------------- /oauth_manager.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "shared.h" 25 | 26 | #include "oauth_manager.h" 27 | 28 | 29 | // TODO(k) Assign default null values https://stackoverflow.com/a/749690 30 | static wd_result _WBoAuth2Init(WBoAuth2Struct* wbo) { 31 | #define CHECKFIELD(FD) result &= (NULL != wbo->FD); 32 | #define INITFIELD(FD) wbo->FD = calloc(1, sizeof(char));CHECKFIELD(FD) 33 | bool result = true; 34 | INITFIELD(access_token); 35 | INITFIELD(refresh_token); 36 | INITFIELD(scope); 37 | INITFIELD(token_type); 38 | wbo->expires_in = 0; 39 | return result ? WNDL_OK : WNDL_ERROR; 40 | #undef INITFIELD 41 | #undef CHECKFIELD 42 | } 43 | 44 | static void _WBoAuth2Cleanup(WBoAuth2Struct* wbo) { 45 | #define FREEFIELD(FD) free(wbo->FD);wbo->FD = NULL; 46 | FREEFIELD(access_token); 47 | FREEFIELD(refresh_token); 48 | FREEFIELD(scope); 49 | FREEFIELD(token_type); 50 | wbo->expires_in = 0; 51 | #undef FREEFIELD 52 | } 53 | -------------------------------------------------------------------------------- /oauth_manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #ifndef OAUTH_MANAGER_H 18 | #define OAUTH_MANAGER_H 19 | 20 | #include 21 | 22 | typedef struct WBoAuth2Struct { 23 | char* access_token; 24 | 25 | char* refresh_token; 26 | 27 | char* scope; 28 | 29 | char* token_type; 30 | 31 | // TODO(k) why 32 ? 32 | uint32_t expires_in; 33 | 34 | } WBoAuth2Struct; 35 | 36 | #endif//OAUTH_MANAGER_H 37 | -------------------------------------------------------------------------------- /perform_entries.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "shared.h" 24 | 25 | #include "configmanager.h" 26 | #include "entries_common.h" 27 | #include "http_request.h" 28 | 29 | #include "perform_entries.h" 30 | 31 | static bool _IsEntriesAlreadyDownloaded(const WBEntry* wbe); 32 | //static void _PerformEverything(const WBEntry* wbe, const WBoAuthCred* wbcred); 33 | 34 | /* 35 | * Function: WBConfigForgeDownloadURL 36 | * ---------------------------- 37 | * Compute the url for downloading an entry using credentials 38 | * 39 | * wbe: a pointer to a WBEntry 40 | * wbcred: a pointer to a WBoAuthCred 41 | * 42 | * returns: an url if succeeds, a null pointer otherwise. 43 | */ 44 | char* WBConfigForgeDownloadURL(const WBEntry* wbe, const WBoAuthCred* wbcred) { 45 | 46 | char* url; 47 | int sprinted; 48 | 49 | // Compute size needed to store downloading url from the MASK 50 | // substracting % format and adding strings size 51 | const size_t url_size = ( sizeof(DOWNLOAD_URL_MASK) 52 | - (2 * (sizeof("%s") - 1) + (sizeof("%lu") - 1)) //minusformats 53 | + MAX_INT_STRLEN//plusmaxintsize 54 | + strlen(wbcred->wallabag_host) 55 | + strlen(wbcred->token) 56 | ) * sizeof(char); 57 | 58 | // Usage of calloc maybe malloc is sufficient 59 | url = calloc(url_size + 1, sizeof(char)); 60 | 61 | // Check if calloc fails 62 | if (NULL == url) { 63 | // In this case, error then quit function 64 | fprintf(stderr, "Cannot allocate download url"); 65 | return NULL; 66 | } 67 | 68 | // build url with mask and fields but limit the size 69 | sprinted = snprintf(url, url_size, DOWNLOAD_URL_MASK, wbcred->wallabag_host, 70 | wbe->id, wbcred->token); 71 | 72 | // Check if a minimum size is really snprinted 73 | if (1 > sprinted) { 74 | // In this case, displays error, free url and quit 75 | fprintf(stderr, "Cannot sprintf download url"); 76 | free(url); 77 | return NULL; 78 | } 79 | 80 | // Return a pointer to URL, must be freed somewhere later ! 81 | return url; 82 | } 83 | 84 | /* 85 | * Function: GetEntryFileName 86 | * ---------------------------- 87 | * Compute the file name for storing an entry on disk 88 | * 89 | * wbe: a pointer to a WBEntry 90 | * 91 | * returns: a filename based on ENTRY_MASK if succeeds, 92 | * and a null pointer otherwise. 93 | */ 94 | char* GetEntryFileName(const WBEntry* wbe) { 95 | char* result; 96 | size_t realsize; 97 | 98 | // We need the length of ENTRY_MASK minus size of parameters 99 | // and add 8 characters 100 | realsize = (sizeof(ENTRY_MASK) 101 | - (sizeof("%08lx") - 1) 102 | + 8) * sizeof(char); 103 | 104 | // Allocate result with "realsize+1" zeros 105 | result = calloc(realsize + 1, sizeof(char)); 106 | 107 | if (NULL == result) { 108 | fprintf(stderr, "Cannot calloc entry file name"); 109 | } else { 110 | // Compute filename and store it in result 111 | int sprinted = snprintf(result, realsize, ENTRY_MASK, wbe->id); 112 | 113 | // Check if snprintf works 114 | if (0 >= sprinted) { 115 | fprintf(stderr, "Cannot snprintf entry file name"); 116 | free(result); 117 | result = NULL; 118 | } 119 | } 120 | 121 | return result; 122 | } 123 | 124 | /* 125 | * Function: IsEbookAlreadyDownloaded 126 | * ---------------------------- 127 | * Basically, checks whether a file already exists 128 | * 129 | * ebookfile: a pointer to a filename 130 | * 131 | * returns: true if file exists and size > 0, returns 132 | * false otherwise. 133 | */ 134 | bool IsEbookAlreadyDownloaded(const char* ebookfile) { 135 | struct stat fs_stat = {0}; 136 | bool result = false; 137 | 138 | if (stat(ebookfile, &fs_stat) == 0) { 139 | result = (fs_stat.st_size > 0); 140 | } 141 | 142 | return result; 143 | } 144 | 145 | /* 146 | * Function: _PerformEverything 147 | * ---------------------------- 148 | * For tests only : do not use. 149 | * 150 | * wbe: a pointer to a WBEntry 151 | * wbcred: a pointer to a WBoAuthCred 152 | * 153 | * returns: true if file exists and size > 0, returns 154 | * false otherwise. 155 | */ 156 | static void _TestPerformEverything(const WBEntry* wbe, const WBoAuthCred* wbcred) { 157 | 158 | char* filename; 159 | bool is_already_downloaded; 160 | EnsureEbookDirExists(); 161 | 162 | filename = GetEntryFileName(wbe); 163 | 164 | if (NULL == filename) { 165 | return; 166 | } 167 | 168 | is_already_downloaded = _IsEntriesAlreadyDownloaded(wbe); 169 | 170 | if (!is_already_downloaded) { 171 | char* url = WBConfigForgeDownloadURL(wbe, wbcred); 172 | GetEbook(url, filename); 173 | free(url); 174 | } 175 | 176 | free(filename); 177 | } 178 | 179 | // TODO(k) 1/ Rename IsEbookAlreadyDownloaded 2/ use it on IsEntriesAlreadyDownloaded 180 | static bool _IsEntriesAlreadyDownloaded(const WBEntry* wbe) { 181 | struct stat fs_stat = {0}; 182 | bool result; 183 | char* filename = GetEntryFileName(wbe); 184 | 185 | if (NULL == filename) { 186 | result = false; 187 | } else if (stat(filename, &fs_stat) == 0) { 188 | result = (fs_stat.st_size > 0); 189 | } else { 190 | result = false; 191 | } 192 | 193 | free(filename); 194 | return result; 195 | } 196 | -------------------------------------------------------------------------------- /perform_entries.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #ifndef PERFORM_ENTRIES_H_INCLUDED 18 | #define PERFORM_ENTRIES_H_INCLUDED 19 | 20 | #include "configmanager.h" 21 | #include "entries_common.h" 22 | 23 | // TODO(k) Add test 24 | bool IsEbookAlreadyDownloaded(const char* ebookfile); 25 | 26 | char* WBConfigForgeDownloadURL(const WBEntry* wbe, 27 | const WBoAuthCred* wbcred); 28 | 29 | char* GetEntryFileName(const WBEntry* wbe); 30 | 31 | #endif//PERFORM_ENTRIES_H_INCLUDED 32 | -------------------------------------------------------------------------------- /shared.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "shared.h" 24 | 25 | /* 26 | * Function: EnsureEbookDirExists 27 | * -------------------- 28 | * Check if the directory to store ebook exists. 29 | * If not, create it in read write access mode for owner 30 | * 31 | * no parameter. 32 | * 33 | * ro returned value. 34 | */ 35 | void EnsureEbookDirExists(void) { 36 | struct stat fs_stat = {0}; 37 | 38 | if (stat(ENTRY_MASK_DIR, &fs_stat) == -1) { 39 | mkdir(ENTRY_MASK_DIR, 0700); 40 | } 41 | } 42 | 43 | /* 44 | * Function: StoreContent 45 | * -------------------- 46 | * Store the "n" bytes of content of string source in string destination. 47 | * "n" is the content size capped by LIMIT_DYNAMIC_STRING. 48 | * 49 | * src: pointer to the source string 50 | * contentsize: the number of char to transfert 51 | * dest: adress to write content 52 | * 53 | * returns: WNDL_OK if everything is ok. An error plus WNDL_ERROR otherwise. 54 | */ 55 | wd_result StoreContent(const char* src, size_t contentsize, char** dest) { 56 | 57 | wd_result result = WNDL_OK; 58 | 59 | // Compute the amount of memory to allocate 60 | const size_t realsize = MIN(contentsize, LIMIT_DYNAMIC_STRING) * sizeof(char); 61 | 62 | // If dest is null 63 | if (NULL == *dest) { 64 | // then we allocate and fill with zeros 65 | *dest = calloc((realsize + 1), sizeof(char)); 66 | } else { 67 | // pointer already exists, the we reallocate 68 | *dest = realloc(*dest, (realsize + 1) * sizeof(char)); 69 | } 70 | 71 | // If memory allocation fails 72 | if (NULL == *dest) { 73 | // then show an error message 74 | fprintf(stderr, "%s", "not enough memory (realloc returned NULL)\n"); 75 | // and stop here with and error 76 | result = WNDL_ERROR; 77 | } else { 78 | // Copy realsize bytes from src to dest 79 | strncpy(*dest, src, realsize); 80 | // just to be sure dest is really null terminated 81 | *(*dest + realsize) = 0; 82 | } 83 | 84 | return result; 85 | } 86 | -------------------------------------------------------------------------------- /shared.h: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #ifndef SHARED_H_INCLUDED 18 | #define SHARED_H_INCLUDED 19 | 20 | #include 21 | #include 22 | 23 | #ifdef __arm__ 24 | #define DBUS_CMD "/usr/bin/dbus-send" 25 | #else 26 | #define DBUS_CMD "/bin/echo" 27 | #endif 28 | 29 | #define DBUS_ARGS "--system","/default","com.lab126.powerd.resuming","int32:1" 30 | 31 | //TODO(k) Ugly! 32 | #define MAX_INT_STRLEN (sizeof("4294967295")) 33 | 34 | //#define WNDL_ERROR (-1) 35 | //#define WNDL_OK (0) 36 | 37 | #define LIMIT_DYNAMIC_STRING (4096) 38 | 39 | #define MIN_CONFFILE_SIZE (50) 40 | #define MAX_CONFFILE_SIZE (4096) 41 | 42 | #define AUTH_URL_MASK "%s/oauth/v2/token?grant_type=password&client_id=%s&client_secret=%s&username=%s&password=%s" 43 | 44 | #define FORMAT_EXPORT "mobi" 45 | 46 | #ifdef __arm__ 47 | #define ENTRY_MASK_DIR "/mnt/base-us/documents/wallabag" 48 | #else 49 | #define ENTRY_MASK_DIR "./entries" 50 | #endif 51 | 52 | #define ENTRY_MASK ENTRY_MASK_DIR "/%08lx." FORMAT_EXPORT 53 | 54 | #define MAXIMUM_ENTRIES (500) 55 | #define SMAXIMUM_ENTRIES "500" 56 | 57 | #define DOWNLOAD_URL_MASK "%s/api/entries/%lu/export." FORMAT_EXPORT "?access_token=%s" 58 | //#define FETCH_ENTRIES_MASK "http://%s/api/entries.json?access_token=%s&perPage=" SMAXIMUM_ENTRIES "&page=1&since=%d&sort=created" 59 | #define FETCH_ENTRIES_MASK "%s/api/entries.json?access_token=%s&perPage=" SMAXIMUM_ENTRIES "&page=1&since=%u" 60 | 61 | #define DEFAULT_CONFIG_FILE "./wallindle.cfg" 62 | 63 | #define UP_TO_X_DAYS (7) 64 | 65 | #define WALLINDLE_USERAGENT ("agent-ckg-fait-mumuse-avec-libcurl/1.0") 66 | 67 | typedef enum wd_result { 68 | WNDL_OK, 69 | WNDL_ERROR 70 | } wd_result; 71 | 72 | 73 | wd_result StoreContent(const char* src, size_t contentsize, char** dest); 74 | 75 | void EnsureEbookDirExists(void); 76 | #endif//SHARED_H_INCLUDED 77 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-O0 -g -m64 -std=iso9899:1999 3 | # -Wunused-function 4 | # -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \ 5 | # -Wno-missing-braces -Wextra -Wno-missing-field-initializers -Wformat=2 \ 6 | # -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith \ 7 | # -Wbad-function-cast -Wstrict-overflow=5 -Wstrict-prototypes -Winline \ 8 | # -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code \ 9 | # -Wlogical-op -Wfloat-equal -Wstrict-aliasing=2 -Wredundant-decls \ 10 | # -Wold-style-definition 11 | # -Werror 12 | 13 | $(eval CURL := `curl-config --libs`) 14 | $(eval CURL := `curl-config --static-libs`) 15 | LDFLAGS=$(CURL) -lm 16 | 17 | EXEC=alltests 18 | 19 | OTHERC=../shared.c ../lib/jsmn/jsmn.c 20 | 21 | # ../configmanager.c ../entries_common.c ../entries_parse.c ../http_request.c \ 22 | # ../json_common.c ../json_entries_parse.c ../json_oauth_parse.c ../oauth_manager.c \ 23 | # ../perform_entries.c ../shared.c \ 24 | # ../lib/jsmn/jsmn.c 25 | 26 | 27 | 28 | all: clean build exec 29 | 30 | build: 31 | $(CC) $(CFLAGS) $(EXEC).c $(OTHERC) -o $(EXEC) $(LDFLAGS) 32 | 33 | exec: 34 | ./$(EXEC) 35 | 36 | valgrind: clean build 37 | valgrind --leak-check=full --show-leak-kinds=all ./$(EXEC) 38 | # valgrind --leak-check=full ./$(EXEC) 39 | 40 | clean: 41 | rm -rf $(EXEC) 42 | 43 | clear: clean 44 | 45 | mrproper: clean 46 | rm -rf $(EXEC) 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/_conffile.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | TEST conffile_check_size_min() { 18 | off_t size49 = GetFileSize("./files/size49.cfg", true); 19 | off_t size50 = GetFileSize("./files/size50.cfg", true); 20 | off_t size51 = GetFileSize("./files/size51.cfg", true); 21 | ASSERT_EQ(size49, -1); 22 | ASSERT_EQ(size50, 50); 23 | ASSERT_EQ(size51, 51); 24 | PASS(); 25 | } 26 | 27 | 28 | TEST conffile_check_size_max() { 29 | off_t size4095 = GetFileSize("./files/size4095.cfg", true); 30 | off_t size4096 = GetFileSize("./files/size4096.cfg", true); 31 | off_t size4097 = GetFileSize("./files/size4097.cfg", true); 32 | off_t size4097bis = GetFileSize("./files/size4097.cfg", false); 33 | ASSERT_EQ(size4095, 4095); 34 | ASSERT_EQ(size4096, 4096); 35 | ASSERT_EQ(size4097, -1); 36 | ASSERT_EQ(size4097bis, 4097); 37 | PASS(); 38 | } 39 | 40 | 41 | TEST conffile_check_config_get_ok() { 42 | WBoAuthCred known = (WBoAuthCred) { 43 | "https://wallabag.example.com", 44 | "2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo", 45 | "4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g", 46 | "root", "sV5G/aTjYRcNkSlTOsZuB78YG.", "" 47 | }; 48 | WBoAuthCred a_wbc; 49 | WBConfigInit(&a_wbc); 50 | wd_result retourWD = _WBConfigGet(&a_wbc, "./files/wallindle.cfg"); 51 | bool result1 = _TestConfigCompare(&known, &a_wbc); 52 | bool result2 = _TestConfigCompare(&a_wbc, &known); 53 | WBConfigCleanup(&a_wbc); 54 | ASSERT_EQ(retourWD, WNDL_OK); 55 | ASSERT_EQ(true, result1); 56 | ASSERT_EQ(true, result2); 57 | PASS(); 58 | } 59 | 60 | TEST conffile_check_config_get_not_ok() { 61 | WBoAuthCred a_wbc; 62 | WBConfigInit(&a_wbc); 63 | wd_result retour50 = _WBConfigGet(&a_wbc, "./files/size50.cfg"); 64 | wd_result retour51 = _WBConfigGet(&a_wbc, "./files/size51.cfg"); 65 | WBConfigCleanup(&a_wbc); 66 | ASSERT_EQ(retour50, WNDL_ERROR); 67 | ASSERT_EQ(retour51, WNDL_ERROR); 68 | PASS(); 69 | } 70 | 71 | TEST conffile_check_forgedurl_ok() { 72 | WBoAuthCred known = (WBoAuthCred) { 73 | "https://wallabag.example.com", 74 | "2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo", 75 | "4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g", 76 | "root", "sV5G/aTjYRcNkSlTOsZuB78YG.", "" 77 | }; 78 | char* forged_url = WBConfigForgeoAuthURL(&known); 79 | const char* WANTED = 80 | "https://wallabag.example.com/oauth/v2/token?grant_type=password&client_id=2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo&client_secret=4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g&username=root&password=sV5G/aTjYRcNkSlTOsZuB78YG."; 81 | ASSERT_STR_EQ(WANTED, forged_url); 82 | free(forged_url); 83 | PASS(); 84 | } 85 | 86 | TEST conffile_check_forgedurl_not_ok() { 87 | WBoAuthCred known = (WBoAuthCred) { 88 | "https://wallabag.example.com", 89 | "2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo", 90 | "4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g", 91 | "root", "sV5G/aTjYRcNkSlTOsZuB78YG.", "" 92 | }; 93 | char* forged_url = WBConfigForgeoAuthURL(&known); 94 | const char* WANTED = 95 | "hXXps://wallabag.example.com/oauth/v2/token?grant_type=password&client_id=2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo&client_secret=4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g&username=root&password=sV5G/aTjYRcNkSlTOsZuB78YG."; 96 | const bool result = (0 != strcmp(WANTED, forged_url)); 97 | free(forged_url); 98 | ASSERT(result); 99 | PASS(); 100 | } 101 | 102 | TEST conffile_check_forgedurl_ok2() { 103 | WBoAuthCred a_wbc; 104 | WBConfigInit(&a_wbc); 105 | wd_result retourWD = _WBConfigGet(&a_wbc, "./files/wallindle.cfg"); 106 | ASSERT_EQ(retourWD, WNDL_OK); 107 | char* forged_url = WBConfigForgeoAuthURL(&a_wbc); 108 | const char* WANTED = 109 | "https://wallabag.example.com/oauth/v2/token?grant_type=password&client_id=2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo&client_secret=4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g&username=root&password=sV5G/aTjYRcNkSlTOsZuB78YG."; 110 | ASSERT_STR_EQ(WANTED, forged_url); 111 | WBConfigCleanup(&a_wbc); 112 | free(forged_url); 113 | PASS(); 114 | } 115 | TEST conffile_check_forgedurl_not_ok2() { 116 | WBoAuthCred a_wbc; 117 | WBConfigInit(&a_wbc); 118 | wd_result retourWD = _WBConfigGet(&a_wbc, "./files/wallindle.cfg"); 119 | ASSERT_EQ(retourWD, WNDL_OK); 120 | char* forged_url = WBConfigForgeoAuthURL(&a_wbc); 121 | const char* WANTED = 122 | "hXXp://wallabag.example.com/oauth/v2/token?grant_type=password&client_id=2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo&client_secret=4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g&username=root&password=sV5G/aTjYRcNkSlTOsZuB78YG."; 123 | const bool result = (0 != strcmp(WANTED, forged_url)); 124 | WBConfigCleanup(&a_wbc); 125 | free(forged_url); 126 | ASSERT(result); 127 | PASS(); 128 | } 129 | 130 | TEST conffile_check_default() { 131 | WBoAuthCred a_wbc1; 132 | WBoAuthCred a_wbc2; 133 | WBConfigInit(&a_wbc1); 134 | WBConfigInit(&a_wbc2); 135 | wd_result retourWD1 = _WBConfigGet(&a_wbc1, "./files/wallindle.cfg"); 136 | wd_result retourWD2 = WBConfigGet(&a_wbc2); 137 | bool result1 = _TestConfigCompare(&a_wbc1, &a_wbc2); 138 | bool result2 = _TestConfigCompare(&a_wbc2, &a_wbc1); 139 | WBConfigCleanup(&a_wbc1); 140 | WBConfigCleanup(&a_wbc2); 141 | ASSERT_EQ(retourWD1, WNDL_OK); 142 | ASSERT_EQ(retourWD2, WNDL_OK); 143 | ASSERT_EQ(true, result1); 144 | ASSERT_EQ(true, result2); 145 | PASS(); 146 | } 147 | 148 | TEST conffile_check_nonexistant_config() { 149 | WBoAuthCred known = (WBoAuthCred) { 150 | "wallabag.example.com", 151 | "2_1xyggA5982e8oscs08os4ckckw00gcscs4g404sg44gg4gowoo", 152 | "4u50vzwnrdwgo84c8wg8sgwskks888wskkc8o04o44kwg4080g", 153 | "root", "sV5G/aTjYRcNkSlTOsZuB78YG.", "" 154 | }; 155 | WBoAuthCred a_wbc; 156 | WBConfigInit(&a_wbc); 157 | int retourWD = _WBConfigGet(&a_wbc, "./files/nonexistant.cfg"); 158 | bool result1 = _TestConfigCompare(&known, &a_wbc); 159 | bool result2 = _TestConfigCompare(&a_wbc, &known); 160 | WBConfigCleanup(&a_wbc); 161 | ASSERT_EQ(retourWD, WNDL_ERROR); 162 | ASSERT_EQ(false, result1); 163 | ASSERT_EQ(false, result2); 164 | PASS(); 165 | } 166 | 167 | SUITE(_conffile) { 168 | RUN_TEST(conffile_check_size_min); 169 | RUN_TEST(conffile_check_size_max); 170 | RUN_TEST(conffile_check_config_get_ok); 171 | RUN_TEST(conffile_check_config_get_not_ok); 172 | RUN_TEST(conffile_check_forgedurl_ok); 173 | RUN_TEST(conffile_check_forgedurl_not_ok); 174 | RUN_TEST(conffile_check_forgedurl_ok2); 175 | RUN_TEST(conffile_check_forgedurl_not_ok2); 176 | RUN_TEST(conffile_check_default); 177 | RUN_TEST(conffile_check_nonexistant_config); 178 | } 179 | -------------------------------------------------------------------------------- /test/_entriescommon.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | TEST entriescommon_geturl() { 18 | WBoAuthCred wba = (WBoAuthCred) { 19 | "https://exAmple.org", "400", 20 | "qlmksd,qcpsdqslkdqs,kdqjsmdl,qj", 21 | "mqimqsdicmqsx 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | TEST httprequest_ok() { 18 | const char* expected = "{\"string\": \"Hello wallindle test :-)\"}"; 19 | const char* url = "http://dsl.cekage.net/wallindle.json"; 20 | 21 | MemoryStruct curlresponse = (MemoryStruct) {NULL, 0}; 22 | 23 | wd_result result = GetJSON(url, &curlresponse); 24 | 25 | ASSERT_EQ(WNDL_OK, result); 26 | ASSERT_STR_EQ(expected, curlresponse.memory); 27 | free(curlresponse.memory); 28 | 29 | PASS(); 30 | } 31 | 32 | TEST httpSrequest_ok() { 33 | const char* expected = "{\"string\": \"Hello wallindle test :-)\"}"; 34 | const char* url = "https://raw.githubusercontent.com/cekage/wallindle/master/test/files/wallindle.json"; 35 | 36 | MemoryStruct curlresponse = (MemoryStruct) {NULL, 0}; 37 | 38 | wd_result result = GetJSON(url, &curlresponse); 39 | 40 | ASSERT_EQ(WNDL_OK, result); 41 | ASSERT_STR_EQ(expected, curlresponse.memory); 42 | free(curlresponse.memory); 43 | PASS(); 44 | } 45 | 46 | SUITE(_httprequest) { 47 | RUN_TEST(httprequest_ok); 48 | RUN_TEST(httpSrequest_ok); 49 | } 50 | -------------------------------------------------------------------------------- /test/_jsonauth.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | TEST jsonauth_get_ok() { 18 | const char* EXPECTED_TOKEN = 19 | "MTZhYTFiNjIwMGJhZmEyMmFlMWExZmU5YmEzZjhkMjU3ZTU0NWI5MTQ2Yjg3YmE2NzNkN2UxOWY5YWUzOWYzOQ"; 20 | 21 | char* jsoncontent; 22 | char* token; 23 | 24 | jsoncontent = _TestReadoAuthJsonFile("./files/token_ok.json"); 25 | ASSERT(NULL != jsoncontent); 26 | 27 | token = ExtractoAuth2Token(jsoncontent); 28 | ASSERT(NULL != token); 29 | ASSERT(strcmp(EXPECTED_TOKEN, token) == 0); 30 | 31 | free(jsoncontent); 32 | free(token); 33 | PASS(); 34 | } 35 | 36 | TEST jsonauth_get_nok() { 37 | const char* EXPECTED_TOKEN = "MTZhYTFiNjIw"; 38 | 39 | char* jsoncontent; 40 | char* token; 41 | 42 | jsoncontent = _TestReadoAuthJsonFile("./files/token_ok.json"); 43 | ASSERT(NULL != jsoncontent); 44 | 45 | token = ExtractoAuth2Token(jsoncontent); 46 | ASSERT(NULL != token); 47 | ASSERT(strcmp(EXPECTED_TOKEN, token) != 0); 48 | 49 | free(jsoncontent); 50 | free(token); 51 | PASS(); 52 | } 53 | 54 | TEST jsonauth_get_nok_accesstoken() { 55 | char* jsoncontent; 56 | char* token; 57 | 58 | jsoncontent = _TestReadoAuthJsonFile("./files/token_error_accesstoken.json"); 59 | ASSERT(NULL != jsoncontent); 60 | 61 | token = ExtractoAuth2Token(jsoncontent); 62 | ASSERT(NULL == token); 63 | 64 | free(jsoncontent); 65 | free(token); 66 | PASS(); 67 | } 68 | 69 | TEST jsonauth_get_nok_expiresin() { 70 | char* jsoncontent; 71 | char* token; 72 | 73 | jsoncontent = _TestReadoAuthJsonFile("./files/token_error_expiresin.json"); 74 | ASSERT(NULL != jsoncontent); 75 | 76 | token = ExtractoAuth2Token(jsoncontent); 77 | ASSERT(NULL != token); 78 | 79 | free(jsoncontent); 80 | free(token); 81 | PASS(); 82 | } 83 | 84 | TEST jsonauth_get_nok_refreshtoken() { 85 | char* jsoncontent; 86 | char* token; 87 | 88 | jsoncontent = _TestReadoAuthJsonFile("./files/token_error_refreshtoken.json"); 89 | ASSERT(NULL != jsoncontent); 90 | 91 | token = ExtractoAuth2Token(jsoncontent); 92 | ASSERT(NULL != token); 93 | 94 | free(jsoncontent); 95 | free(token); 96 | PASS(); 97 | } 98 | 99 | TEST jsonauth_get_nok_scope() { 100 | char* jsoncontent; 101 | char* token; 102 | 103 | jsoncontent = _TestReadoAuthJsonFile("./files/token_error_scope.json"); 104 | ASSERT(NULL != jsoncontent); 105 | 106 | token = ExtractoAuth2Token(jsoncontent); 107 | ASSERT(NULL != token); 108 | 109 | free(jsoncontent); 110 | free(token); 111 | PASS(); 112 | } 113 | 114 | TEST jsonauth_get_nok_tokentype() { 115 | char* jsoncontent; 116 | char* token; 117 | 118 | jsoncontent = _TestReadoAuthJsonFile("./files/token_error_tokentype.json"); 119 | ASSERT(NULL != jsoncontent); 120 | 121 | token = ExtractoAuth2Token(jsoncontent); 122 | ASSERT(NULL != token); 123 | 124 | free(jsoncontent); 125 | free(token); 126 | PASS(); 127 | } 128 | 129 | TEST jsonauth_get_nok_notjson() { 130 | char* jsoncontent; 131 | char* token; 132 | 133 | jsoncontent = _TestReadoAuthJsonFile("./files/token_error_notjson.json"); 134 | ASSERT(NULL != jsoncontent); 135 | 136 | token = ExtractoAuth2Token(jsoncontent); 137 | ASSERT(NULL == token); 138 | 139 | free(jsoncontent); 140 | free(token); 141 | PASS(); 142 | } 143 | 144 | TEST jsonauth_get_nok_nonexistant() { 145 | char* jsoncontent; 146 | char* token; 147 | 148 | jsoncontent = _TestReadoAuthJsonFile("./files/nonexistant.json"); 149 | ASSERT(NULL == jsoncontent); 150 | 151 | token = ExtractoAuth2Token(jsoncontent); 152 | ASSERT(NULL == token); 153 | 154 | free(jsoncontent); 155 | free(token); 156 | PASS(); 157 | } 158 | 159 | SUITE(_jsonauth) { 160 | RUN_TEST(jsonauth_get_ok); 161 | RUN_TEST(jsonauth_get_nok); 162 | RUN_TEST(jsonauth_get_nok_accesstoken); 163 | RUN_TEST(jsonauth_get_nok_expiresin); 164 | RUN_TEST(jsonauth_get_nok_refreshtoken); 165 | RUN_TEST(jsonauth_get_nok_scope); 166 | RUN_TEST(jsonauth_get_nok_tokentype); 167 | RUN_TEST(jsonauth_get_nok_notjson); 168 | RUN_TEST(jsonauth_get_nok_nonexistant); 169 | } 170 | -------------------------------------------------------------------------------- /test/_jsonentries.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | TEST jsonentries_get_ok() { 18 | char* jsoncontent; 19 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_10.json"); 20 | ASSERT(NULL != jsoncontent); 21 | free(jsoncontent); 22 | PASS(); 23 | } 24 | 25 | TEST jsonentries_get_count() { 26 | char* jsoncontent; 27 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_1.json"); 28 | ASSERT(NULL != jsoncontent); 29 | int count = _GetTokenCount(jsoncontent); 30 | ASSERT_EQ(72, count); 31 | free(jsoncontent); 32 | PASS(); 33 | } 34 | 35 | TEST jsonentries_token_allocation() { 36 | char* jsoncontent; 37 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_1.json"); 38 | ASSERT(NULL != jsoncontent); 39 | int count = _GetTokenCount(jsoncontent); 40 | jsmntok_t* tokens = _AllocateTokens(jsoncontent, count); 41 | free(jsoncontent); 42 | ASSERT(NULL != tokens); 43 | free(tokens); 44 | PASS(); 45 | } 46 | 47 | TEST jsonentries_token_allocation_too_big() { 48 | char* jsoncontent; 49 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_1.json"); 50 | ASSERT(NULL != jsoncontent); 51 | jsmntok_t* tokens = _AllocateTokens(jsoncontent, 800); 52 | free(jsoncontent); 53 | ASSERT_EQ(NULL, tokens); 54 | free(tokens); 55 | PASS(); 56 | } 57 | 58 | TEST jsonentries_token_allocation_too_low() { 59 | char* jsoncontent; 60 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_1.json"); 61 | ASSERT(NULL != jsoncontent); 62 | jsmntok_t* tokens = _AllocateTokens(jsoncontent, 12); 63 | free(jsoncontent); 64 | ASSERT_EQ(NULL, tokens); 65 | free(tokens); 66 | PASS(); 67 | } 68 | 69 | TEST jsonentries_token_search_embedded() { 70 | char* jsoncontent; 71 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_1.json"); 72 | ASSERT(NULL != jsoncontent); 73 | int count = _GetTokenCount(jsoncontent); 74 | ASSERT(count > 0); 75 | jsmntok_t* tokens = _AllocateTokens(jsoncontent, count); 76 | ASSERT(NULL != tokens); 77 | 78 | int embedded_pos = 1; 79 | _GetJsonKeyPosition(jsoncontent, tokens, count, "_embedded", 80 | JSMN_OBJECT, &embedded_pos); 81 | free(jsoncontent); 82 | ASSERT_EQ(24, embedded_pos); 83 | free(tokens); 84 | PASS(); 85 | } 86 | 87 | TEST jsonentries_token_search_notembedded() { 88 | char* jsoncontent; 89 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_1.json"); 90 | ASSERT(NULL != jsoncontent); 91 | int count = _GetTokenCount(jsoncontent); 92 | ASSERT(count > 0); 93 | jsmntok_t* tokens = _AllocateTokens(jsoncontent, count); 94 | ASSERT(NULL != tokens); 95 | 96 | int embedded_pos = 1; 97 | _GetJsonKeyPosition(jsoncontent, tokens, count, "_notembedded", 98 | JSMN_OBJECT, &embedded_pos); 99 | free(jsoncontent); 100 | ASSERT_EQ(count, embedded_pos); 101 | free(tokens); 102 | PASS(); 103 | } 104 | 105 | TEST jsonentries_token_search_items() { 106 | char* jsoncontent; 107 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_1.json"); 108 | ASSERT(NULL != jsoncontent); 109 | int count = _GetTokenCount(jsoncontent); 110 | ASSERT(count > 0); 111 | jsmntok_t* tokens = _AllocateTokens(jsoncontent, count); 112 | ASSERT(NULL != tokens); 113 | int key_pos = 1; 114 | _GetJsonKeyPosition(jsoncontent, tokens, count, "_embedded", 115 | JSMN_OBJECT, &key_pos); 116 | _GetJsonKeyPosition(jsoncontent, tokens, count, "items", JSMN_ARRAY, 117 | &key_pos); 118 | free(jsoncontent); 119 | ASSERT_EQ(26, key_pos); 120 | free(tokens); 121 | PASS(); 122 | } 123 | TEST jsonentries_token_search_notitems() { 124 | char* jsoncontent; 125 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_1.json"); 126 | ASSERT(NULL != jsoncontent); 127 | int count = _GetTokenCount(jsoncontent); 128 | ASSERT(count > 0); 129 | jsmntok_t* tokens = _AllocateTokens(jsoncontent, count); 130 | ASSERT(NULL != tokens); 131 | int key_pos = 1; 132 | _GetJsonKeyPosition(jsoncontent, tokens, count, "_embedded", 133 | JSMN_OBJECT, &key_pos); 134 | _GetJsonKeyPosition(jsoncontent, tokens, count, "notitems", JSMN_ARRAY, 135 | &key_pos); 136 | free(jsoncontent); 137 | ASSERT_EQ(count, key_pos); 138 | free(tokens); 139 | PASS(); 140 | } 141 | 142 | TEST jsonentries_get_entries() { 143 | char* jsoncontent; 144 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_10.json"); 145 | ASSERT(NULL != jsoncontent); 146 | WBEntry* entries = JsonGetEntries(jsoncontent); 147 | ASSERT(NULL != entries); 148 | // Clean all created_at string 149 | for (int i = 0; i < MAXIMUM_ENTRIES; ++i) { 150 | if (0 == entries[i].id) { break; } 151 | 152 | free(entries[i].created_at); 153 | } 154 | 155 | free(entries); 156 | free(jsoncontent); 157 | PASS(); 158 | } 159 | 160 | TEST jsonentries_perform_entries() { 161 | char* jsoncontent; 162 | jsoncontent = _TestReadEntriesJsonFile("./files/response_ok_total_10.json"); 163 | ASSERT(NULL != jsoncontent); 164 | WBEntry* entries = JsonGetEntries(jsoncontent); 165 | ASSERT(NULL != entries); 166 | WBoAuthCred known = (WBoAuthCred) { 167 | "exAmple.org", "10921029", 168 | "qlmksd,qcpsdqslkdqs,kdqjsmdl,qj", 169 | "mqimqsdicmqsx 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | 18 | 19 | TEST performentries_getfilename() { 20 | WBEntry wbe = (WBEntry) {false, false, 0x123, "DaTe"}; 21 | char* filename = GetEntryFileName(&wbe); 22 | printf("filename = %s\n", filename); 23 | ASSERT_STR_EQ("./entries/00000123.mobi", filename); 24 | free(filename); 25 | PASS(); 26 | } 27 | 28 | TEST performentries_geturl() { 29 | WBEntry wbe = (WBEntry) {false, false, 0x123, "DaTe"}; 30 | 31 | WBoAuthCred wba = (WBoAuthCred) { 32 | "https://exAmple.org", "10921029", 33 | "qlmksd,qcpsdqslkdqs,kdqjsmdl,qj", 34 | "mqimqsdicmqsx 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include "../configmanager.h" 18 | 19 | TEST wbac_compare_ok() { 20 | WBoAuthCred known = (WBoAuthCred) { 21 | "example.org", "10921029", 22 | "qlmksd,qcpsdqslkdqs,kdqjsmdl,qj", 23 | "mqimqsdicmqsx 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | TEST wbac_init_ok() { 18 | WBoAuthCred wac_default; 19 | int result = WBConfigInit(&wac_default); 20 | WBConfigCleanup(&wac_default); 21 | ASSERT_EQ(WNDL_OK, result); 22 | PASS(); 23 | } 24 | 25 | // Makes valgrind crying :/ 26 | TEST wbac_init_double_init() { 27 | WBoAuthCred wac_default; 28 | // WBConfigInit(&wac_default); 29 | int result = WBConfigInit(&wac_default); 30 | WBConfigCleanup(&wac_default); 31 | ASSERT_EQ(WNDL_OK, result); 32 | PASS(); 33 | } 34 | 35 | TEST wbac_init_double_cleanup() { 36 | WBoAuthCred wac_default; 37 | int result = WBConfigInit(&wac_default); 38 | WBConfigCleanup(&wac_default); 39 | WBConfigCleanup(&wac_default); 40 | ASSERT_EQ(WNDL_OK, result); 41 | PASS(); 42 | } 43 | 44 | TEST wbac_loop_init_cleanup() { 45 | WBoAuthCred wac_default; 46 | 47 | for (int i = 0; i < 8192; ++i) { 48 | int result = WBConfigInit(&wac_default); 49 | WBConfigCleanup(&wac_default); 50 | ASSERT_EQ(WNDL_OK, result); 51 | } 52 | 53 | PASS(); 54 | } 55 | 56 | SUITE(_wbac_init) { 57 | RUN_TEST(wbac_init_ok); 58 | RUN_TEST(wbac_init_double_init); 59 | RUN_TEST(wbac_init_double_cleanup); 60 | RUN_TEST(wbac_loop_init_cleanup); 61 | } 62 | -------------------------------------------------------------------------------- /test/_wbac_setstring.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include "../configmanager.h" 18 | 19 | TEST wbac_setstring_ok() { 20 | WBoAuthCred known = (WBoAuthCred) { 21 | "exAmple.org", "10921029", 22 | "qlmksd,qcpsdqslkdqs,kdqjsmdl,qj", 23 | "mqimqsdicmqsx 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | TEST wboa_init_ok() { 18 | WBoAuth2Struct wbo; 19 | int result = _WBoAuth2Init(&wbo); 20 | _WBoAuth2Cleanup(&wbo); 21 | ASSERT_EQ(WNDL_OK, result); 22 | PASS(); 23 | } 24 | 25 | // Makes valgrind crying :/ 26 | TEST wboa_init_double_init() { 27 | WBoAuth2Struct wbo; 28 | int result; 29 | result = _WBoAuth2Init(&wbo); 30 | // result = WBoAuth2Init(&wbo); 31 | _WBoAuth2Cleanup(&wbo); 32 | ASSERT_EQ(WNDL_OK, result); 33 | PASS(); 34 | } 35 | 36 | TEST wboa_init_double_cleanup() { 37 | WBoAuth2Struct wbo; 38 | int result = _WBoAuth2Init(&wbo); 39 | _WBoAuth2Cleanup(&wbo); 40 | _WBoAuth2Cleanup(&wbo); 41 | ASSERT_EQ(WNDL_OK, result); 42 | PASS(); 43 | } 44 | 45 | TEST wboa_loop_init_cleanup() { 46 | WBoAuth2Struct wbo; 47 | 48 | for (int i = 0; i < 8192; ++i) { 49 | int result = _WBoAuth2Init(&wbo); 50 | _WBoAuth2Cleanup(&wbo); 51 | ASSERT_EQ(WNDL_OK, result); 52 | } 53 | 54 | PASS(); 55 | } 56 | 57 | TEST wboa_test_StringSet() { 58 | WBoAuth2Struct wbo; 59 | int result = _WBoAuth2Init(&wbo); 60 | int resultset1 = _TestoAuth2StringSet(AUTH_URL_MASK, sizeof(AUTH_URL_MASK), 61 | &wbo.access_token); 62 | int resultset2 = _TestoAuth2StringSet(AUTH_URL_MASK, sizeof(AUTH_URL_MASK), 63 | &wbo.refresh_token); 64 | int resultset3 = _TestoAuth2StringSet(AUTH_URL_MASK, sizeof(AUTH_URL_MASK), 65 | &wbo.scope); 66 | int resultset4 = _TestoAuth2StringSet(AUTH_URL_MASK, sizeof(AUTH_URL_MASK), 67 | &wbo.token_type); 68 | wbo.expires_in = LIMIT_DYNAMIC_STRING; 69 | _WBoAuth2Cleanup(&wbo); 70 | ASSERT_EQ(WNDL_OK, resultset1); 71 | ASSERT_EQ(WNDL_OK, resultset2); 72 | ASSERT_EQ(WNDL_OK, resultset3); 73 | ASSERT_EQ(WNDL_OK, resultset4); 74 | ASSERT_EQ(WNDL_OK, result); 75 | PASS(); 76 | } 77 | 78 | 79 | TEST wboa_test_StringSet_compare() { 80 | WBoAuth2Struct wbo; 81 | int result = _WBoAuth2Init(&wbo); 82 | int resultset1 = _TestoAuth2StringSet(AUTH_URL_MASK, sizeof(AUTH_URL_MASK), 83 | &wbo.access_token); 84 | 85 | ASSERT_EQ(WNDL_OK, resultset1); 86 | ASSERT_EQ(WNDL_OK, result); 87 | ASSERT_STR_EQ(AUTH_URL_MASK, wbo.access_token); 88 | _WBoAuth2Cleanup(&wbo); 89 | PASS(); 90 | } 91 | 92 | 93 | TEST wboa_test_StringSet_truncate_compare() { 94 | WBoAuth2Struct wbo; 95 | int result = _WBoAuth2Init(&wbo); 96 | int resultset1 = _TestoAuth2StringSet(AUTH_URL_MASK, sizeof(AUTH_URL_MASK) / 2, 97 | &wbo.access_token); 98 | ASSERT_STRN_EQ(AUTH_URL_MASK, wbo.access_token, sizeof(AUTH_URL_MASK) / 2); 99 | 100 | _WBoAuth2Cleanup(&wbo); 101 | ASSERT_EQ(WNDL_OK, resultset1); 102 | ASSERT_EQ(WNDL_OK, result); 103 | PASS(); 104 | } 105 | 106 | TEST wboa_test_StringSet_overflow_compare() { 107 | WBoAuth2Struct wbo; 108 | int result = _WBoAuth2Init(&wbo); 109 | int resultset1 = _TestoAuth2StringSet(AUTH_URL_MASK, sizeof(AUTH_URL_MASK) * 2, 110 | &wbo.access_token); 111 | ASSERT_STRN_EQ(AUTH_URL_MASK, wbo.access_token, sizeof(AUTH_URL_MASK) * 2); 112 | 113 | _WBoAuth2Cleanup(&wbo); 114 | ASSERT_EQ(WNDL_OK, resultset1); 115 | ASSERT_EQ(WNDL_OK, result); 116 | PASS(); 117 | } 118 | 119 | TEST wboa_test_print() { 120 | WBoAuth2Struct wbo = (WBoAuth2Struct) {"ok1", "ok2", "ok3", "ok4", 1337}; 121 | _TestoAuth2Print(&wbo); 122 | PASS(); 123 | } 124 | 125 | SUITE(_wboa_init) { 126 | RUN_TEST(wboa_init_ok); 127 | RUN_TEST(wboa_init_double_init); 128 | RUN_TEST(wboa_init_double_cleanup); 129 | RUN_TEST(wboa_loop_init_cleanup); 130 | RUN_TEST(wboa_test_StringSet); 131 | RUN_TEST(wboa_test_StringSet_compare); 132 | RUN_TEST(wboa_test_StringSet_truncate_compare); 133 | RUN_TEST(wboa_test_StringSet_overflow_compare); 134 | RUN_TEST(wboa_test_print); 135 | } 136 | -------------------------------------------------------------------------------- /test/alltests.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include "greatest.h" 18 | 19 | #include "../configmanager.c" 20 | #include "../oauth_manager.c" 21 | #include "../json_oauth_parse.c" 22 | #include "../json_common.c" 23 | #include "../json_entries_parse.c" 24 | #include "../perform_entries.c" 25 | #include "../http_request.c" 26 | #include "../entries_common.c" 27 | 28 | #include "_wbac_init.c" 29 | #include "_wbac_compare.c" 30 | #include "_wbac_setstring.c" 31 | #include "_conffile.c" 32 | //#include "_wboa_init.c" 33 | #include "_jsonauth.c" 34 | #include "_jsonentries.c" 35 | #include "_performentries.c" 36 | #include "_entriescommon.c" 37 | #include "_httprequest.c" 38 | 39 | /* Add definitions that need to be in the test runner's main file. */ 40 | GREATEST_MAIN_DEFS(); 41 | 42 | int main(int argc, char** argv) { 43 | GREATEST_MAIN_BEGIN(); /* command-line arguments, initialization. */ 44 | RUN_SUITE(_wbac_init); 45 | RUN_SUITE(_wbac_compare); 46 | RUN_SUITE(_wbac_setstring); 47 | RUN_SUITE(_conffile); 48 | // RUN_SUITE(_wboa_init); 49 | RUN_SUITE(_jsonauth); 50 | RUN_SUITE(_jsonentries); 51 | RUN_SUITE(_performentries); 52 | RUN_SUITE(_entriescommon); 53 | RUN_SUITE(_httprequest); 54 | GREATEST_MAIN_END(); /* display results */ 55 | } 56 | -------------------------------------------------------------------------------- /test/files/wallindle.json: -------------------------------------------------------------------------------- 1 | {"string": "Hello wallindle test :-)"} -------------------------------------------------------------------------------- /test/wallindle.cfg: -------------------------------------------------------------------------------- 1 | files/wallindle.cfg -------------------------------------------------------------------------------- /wallindle.c: -------------------------------------------------------------------------------- 1 | /* 2 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 3 | Version 2, December 2004 4 | 5 | Copyright (C) 2004 Sam Hocevar 6 | 7 | Everyone is permitted to copy and distribute verbatim or modified 8 | copies of this license document, and changing it is allowed as long 9 | as the name is changed. 10 | 11 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 13 | 14 | 0. You just DO WHAT THE FUCK YOU WANT TO. 15 | */ 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "http_request.h" 27 | #include "json_entries_parse.h" 28 | #include "configmanager.h" 29 | //#include "entries_parse.h" 30 | #include "perform_entries.h" 31 | #include "entries_common.h" 32 | #include "json_oauth_parse.h" 33 | 34 | #include "shared.h" 35 | 36 | static void UpdateKindleCatalog(void ) { 37 | pid_t pid = fork(); 38 | 39 | if (pid == -1) { 40 | fprintf(stderr, "Can't fork\n"); 41 | } else if (pid > 0) { 42 | int status; 43 | 44 | if (-1 == waitpid(pid, &status, 0)) { 45 | printf("Error for waitpid :(\n"); 46 | } 47 | } else { 48 | /*@null@*/ 49 | char* command = DBUS_CMD; 50 | char* arguments[] = {DBUS_CMD, DBUS_ARGS, NULL}; 51 | 52 | if (-1 == execvp(command, arguments)) { 53 | printf("Error for execvp :(\n"); 54 | } 55 | 56 | exit(EXIT_FAILURE); 57 | } 58 | } 59 | 60 | static void ProceedUpdate(WBEntry* entries, WBoAuthCred a_wbc) { 61 | unsigned int i; 62 | 63 | // Iterate entries until MAXIMUM or the first time id is zero 64 | for (i = 0; (i < MAXIMUM_ENTRIES) && (0 != entries[i].id); ++i) { 65 | 66 | char* ebookurl; 67 | // Retrieve file name 68 | char* filename = GetEntryFileName(&entries[i]); 69 | 70 | // Check if filename is null, must not happened ! 71 | if (NULL == filename) { 72 | // in this case, go to next entries 73 | continue; 74 | } 75 | 76 | // // Check if ebook already exists 77 | // if (IsEbookAlreadyDownloaded(filename)) { 78 | // // in this case, free stuff and go to next entries 79 | // free(filename); 80 | // continue; 81 | // } 82 | 83 | printf("Downloading item %lu -> %s \n", entries[i].id, filename); 84 | 85 | // Compute Url for downloading ebook 86 | ebookurl = WBConfigForgeDownloadURL(&entries[i], &a_wbc); 87 | 88 | // If getting ebook raises an error 89 | if (WNDL_ERROR == GetEbook(ebookurl, filename)) { 90 | // then displays error message 91 | printf("fetching %s failed\n", ebookurl); 92 | }; 93 | 94 | free(ebookurl); 95 | free(filename); 96 | 97 | } 98 | } 99 | 100 | // TODO(k) Too long !! 101 | int main(void ) { 102 | char* oauthurl; 103 | char* getentriesurl; 104 | WBEntry* entries; 105 | WBoAuthCred a_wbc; 106 | 107 | // Init auth json with empty values 108 | MemoryStruct authjsonresponse = (MemoryStruct) {NULL, 0}; 109 | // Init entries json with empty values 110 | MemoryStruct entriesjsonresponse = (MemoryStruct) {NULL, 0}; 111 | 112 | // Initialize configuration 113 | if (WNDL_ERROR == WBConfigInit(&a_wbc)) { 114 | WBConfigCleanup(&a_wbc); 115 | exit(EXIT_FAILURE); 116 | } 117 | 118 | // Retrieve config data from config file 119 | if (WNDL_ERROR == WBConfigGet(&a_wbc)) { 120 | WBConfigCleanup(&a_wbc); 121 | exit(EXIT_FAILURE); 122 | } 123 | 124 | // Retrieve the forged url to get auth token 125 | oauthurl = WBConfigForgeoAuthURL(&a_wbc); 126 | 127 | // for debug : 128 | // printf("\noauthurl = \n%s\n", oauthurl); 129 | 130 | // Check if oAuth2 url is correctly build 131 | if (NULL == oauthurl) { 132 | WBConfigCleanup(&a_wbc); 133 | exit(EXIT_FAILURE); 134 | } 135 | 136 | // Check if oAuth2 url gives a json response 137 | if (WNDL_ERROR == GetJSON(oauthurl, &authjsonresponse)) { 138 | free(oauthurl); // Avoiding valgrind warnings 139 | WBConfigCleanup(&a_wbc); 140 | exit(EXIT_FAILURE); 141 | } 142 | 143 | // TODO(k) maybe another way than doubling free ! 144 | free(oauthurl); 145 | 146 | // TODO(k) Avoiding memory leak… 147 | free(a_wbc.token); 148 | // Store the token in the cred object 149 | a_wbc.token = ExtractoAuth2Token(authjsonresponse.memory); 150 | 151 | // No token ? 152 | if (NULL == a_wbc.token) { 153 | // Freeing cred object 154 | WBConfigCleanup(&a_wbc); 155 | // Freeing memory 156 | free(authjsonresponse.memory); 157 | exit(EXIT_FAILURE); 158 | } 159 | 160 | // TODO(k) maybe another way than doubling free ! 161 | free(authjsonresponse.memory); 162 | 163 | getentriesurl = WBEntryFetchingURL(&a_wbc); 164 | 165 | if (WNDL_ERROR == GetJSON(getentriesurl, &entriesjsonresponse)) { 166 | free(getentriesurl); // Avoiding valgrind warnings 167 | exit(EXIT_FAILURE); 168 | } 169 | 170 | // TODO(k) maybe another way than doubling free ! 171 | free(getentriesurl); 172 | 173 | // for debug : 174 | // printf("\nentriesjsonresponse.memory = \n%s\n", entriesjsonresponse.memory); 175 | 176 | entries = JsonGetEntries(entriesjsonresponse.memory); 177 | free(entriesjsonresponse.memory); 178 | 179 | if (NULL != entries) { 180 | unsigned int i; 181 | EnsureEbookDirExists(); 182 | ProceedUpdate(entries, a_wbc); 183 | 184 | for (i = 0; (i < MAXIMUM_ENTRIES) && (0 != entries[i].id); ++i) { 185 | WBEntryCleaup(&entries[i]); 186 | } 187 | 188 | free(entries); 189 | UpdateKindleCatalog(); 190 | } 191 | 192 | WBConfigCleanup(&a_wbc); 193 | 194 | printf("\nMischief Managed!\n"); 195 | return 0; 196 | } 197 | 198 | 199 | --------------------------------------------------------------------------------