├── .gitignore ├── LICENSE ├── README.md ├── credentials1.png ├── credentials2.png ├── editor.png ├── endpoint.jpg ├── examples ├── AuthorizeOnly │ ├── AuthorizeOnly.ino │ └── config.h ├── Gmail │ ├── Gmail.ino │ └── config.h ├── GoogleCalendar │ ├── GoogleCalendar.ino │ └── config.h ├── GoogleDrive │ ├── GoogleDrive.ino │ └── config.h ├── GoogleDrive_ESP32_Task │ ├── GoogleDrive_ESP32_Task.ino │ └── config.h ├── GoogleDrive_logdata │ ├── GoogleDrive_logdata.ino │ └── config.h └── GoogleSheet │ ├── GoogleSheet.ino │ └── config.h ├── extras ├── feathericons.png ├── index.htm ├── index.htm.gz ├── index_htm.h └── reduce_index.sh ├── keywords.txt ├── library.properties ├── php_gauth ├── auth_code.txt ├── endpoint.php ├── getAuthCode.php └── smart-air.png ├── src ├── Base64.h ├── Const.h ├── GoogleCalendar.cpp ├── GoogleCalendar.h ├── GoogleDrive.cpp ├── GoogleDrive.h ├── GoogleFilelist.cpp ├── GoogleFilelist.h ├── GoogleGmail.cpp ├── GoogleGmail.h ├── GoogleOAuth2.cpp ├── GoogleOAuth2.h ├── GoogleSheet.cpp ├── GoogleSheet.h ├── SerialLog.h ├── gaconfig_htm.h └── zlib │ ├── FAQ.md │ ├── README.md │ ├── adler32.c │ ├── compress.c │ ├── crc32.c │ ├── crc32.h │ ├── deflate.c │ ├── deflate.h │ ├── gzclose.c │ ├── gzguts.h │ ├── gzlib.c │ ├── gzread.c │ ├── gzwrite.c │ ├── infback.c │ ├── inffast.c │ ├── inffast.h │ ├── inffixed.h │ ├── inflate.c │ ├── inflate.h │ ├── inftrees.c │ ├── inftrees.h │ ├── trees.c │ ├── trees.h │ ├── uncompr.c │ ├── zconf.h │ ├── zlib.3 │ ├── zlib.h │ ├── zlib.zip │ ├── zutil.c │ └── zutil.h ├── token_helper.png └── ui ├── README.md ├── babel.config.js ├── finalize.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── gapi_config.json ├── index.html ├── ipaddress └── scan ├── readme.md ├── src ├── App.vue ├── assets │ ├── arduino-google-api.vue │ ├── custom-logo.vue │ ├── favicon.ico │ └── favicon.svg ├── components │ ├── BModal.vue │ └── Token.vue ├── main.js └── scss │ └── custom.scss └── vue.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino-Google-API 2 | 3 | ** STILL IN DEVELOPMENT ** Provided as is 4 | 5 | ### Introduction 6 | 7 | With the **GoogleAPI Arduino library**, you can easily authenticate your Espressif (ESP8266 and ESP32) device as an OAuth 2.0 client without user interaction, except for the first time when your application must be authorized to provide the user's consent. 8 | 9 | The first step is to create a new Project in the **Google API console** and set up credentials to obtain a valid **Client ID, Client Secret, API key**, and enable all the required APIs (Drive, Gmail, Sheets, Calendar, etc.). 10 | 11 | You also have to define which [scope](https://developers.google.com/identity/protocols/oauth2/scopes) your application will be able to manage. Follow instructions provided in the [API Console Help](https://support.google.com/googleapi/answer/7037264) for detailed instructions and How-To. To create your project and credentials, visit the page [Google API Console](https://console.developers.google.com/apis/credentials). 12 | 13 | ![Google API credentials](/credentials1.png) 14 | 15 | Client ID, Client Secret, API key and Scope can be created/defined **only once by the developer**. Then, the user has to authorize the application to get a valid **access token** and a **refresh token** to renew the access token when expired. 16 | 17 | The easiest way to use Google's APIs would be using Google's JavaScript OAuth 2.0 for Client-side library provided from Google itself in a webpage hosted on the ESP device. Unfortunately, only top-level domains can be whitelisted as "Authorized JavaScript origins," so this way is impracticable for our purposes. 18 | 19 | This library will authorize your device as a **Web Service** using the OAuth 2.0 endpoint for [Web Server Applications](https://developers.google.com/identity/protocols/oauth2/web-server), and a little web server hosted on ESP is necessary. For your (or your users') convenience, the provided **http://(your_device_address)/token** page can handle all necessary steps in the background and finally save the JSON configuration file in the ESP memory. 20 | 21 | Note that users will be warned about an "unverified App" unless you submit a request to Google for verification if you require it. You can simply skip it for testing purposes or if you don't need to redistribute: just click on _advanced_ and then go to _---your app name---(unsafe)_. 22 | 23 | **Important** 24 | 25 | As you can read in the Google documentation, for this authorization scenario, it is necessary to have an authorized redirect URI as endpoints to which the OAuth 2.0 server can send the generated tokens. If you own a top-level host, I've written a small PHP script, and you can upload it to your server and use it as a redirect URI. 26 | 27 | Another good option for a redirect URI is using a micro-service like [pipedream.com](https://pipedream.com), for example. The free plan will be largely sufficient for most cases (remember, you will need it only once for each user). This is my pipedream [working workflow](https://pipedream.com/@cotestatnt/smart-air-p_mkCk3JW), feel free to copy and use it for your convenience. The redirect URI to be used will be the one generated when you deploy your workflow (something like xxxxxxxxxx.m.pipedream.net). 28 | 29 | The redirect URI has to be inserted in your OAuth 2.0 Client ID credential definition (edit it after creating). Remember also to add https://apis.google.com as an authorized JavaScript origin. 30 | 31 | ![OAuth 2.0 Client ID](/credentials2.png) 32 | 33 | ### Features 34 | 35 | - Authorize application for the allowed scopes 36 | - Save and refresh access token (local filesystem) 37 | 38 | GoogleSheetAPI Class 39 | 40 | - Create spreadsheet on Google Drive 41 | - Create sheets in a provided spreadsheet 42 | - Append rows to spreadsheet (formula supported) 43 | 44 | GoogleDriveAPI Class 45 | 46 | - Create folders on Google Drive 47 | - Upload files on Google Drive 48 | - Update existing files on Google Drive 49 | - Search for a specific file or folder 50 | 51 | GoogleGmailAPI Class 52 | 53 | - Get list of unread messages 54 | - Read metadata of message 55 | - Read message body (snippet or full text) 56 | - Send message to specific address 57 | 58 | ### To do 59 | 60 | - Add support for Calendar API 61 | - Download files (Google Drive API) 62 | - Set metadata for message (Gmail API) 63 | 64 | ### Supported boards 65 | 66 | The library works with the ESP8266 and ESP32 chipset. 67 | 68 | - 1.0.4 Webserver included in the source (no need to load Data folder in the filesystem). 69 | - 1.0.3 Added support for Google Mail API 70 | - 1.0.2 Added support for Google Sheet API 71 | - 1.0.1 Added support for Google Drive API 72 | - 1.0.0 Initial version 73 | -------------------------------------------------------------------------------- /credentials1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/credentials1.png -------------------------------------------------------------------------------- /credentials2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/credentials2.png -------------------------------------------------------------------------------- /editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/editor.png -------------------------------------------------------------------------------- /endpoint.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/endpoint.jpg -------------------------------------------------------------------------------- /examples/AuthorizeOnly/AuthorizeOnly.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // https://github.com/cotestatnt/esp-fs-webserver 4 | 5 | // Timezone definition to obtain the correct time from the NTP server 6 | #define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" 7 | struct tm Time; 8 | 9 | // Filesystem will be used to store access credentials and custom options 10 | #include 11 | #include 12 | #define FILESYSTEM LittleFS 13 | 14 | #include 15 | #ifdef ESP8266 16 | #include 17 | using WebServerClass = ESP8266WebServer; 18 | Session session; 19 | X509List certificate(google_cert); 20 | #elif defined(ESP32) 21 | #include 22 | using WebServerClass = WebServer; 23 | #endif 24 | 25 | #include "config.h" 26 | 27 | /* The webserver it's needed only the first time in order to do OAuth2.0 authorizing workflow */ 28 | WebServerClass server; 29 | FSWebServer myWebServer(FILESYSTEM, server); 30 | 31 | /* The web client used from library */ 32 | WiFiClientSecure client; 33 | 34 | /* The instance of library that will handle authorization token renew */ 35 | GoogleOAuth2 myAuth(FILESYSTEM, client); 36 | const char* hostname = HOSTNAME; 37 | bool authorized = false; 38 | 39 | 40 | //////////////////////////////// NTP Time ///////////////////////////////////////// 41 | void getUpdatedtime(const uint32_t timeout) { 42 | uint32_t start = millis(); 43 | do { 44 | time_t now = time(nullptr); 45 | Time = *localtime(&now); 46 | delay(1); 47 | } while (millis() - start < timeout && Time.tm_year <= (1970 - 1900)); 48 | } 49 | 50 | //////////////////////////////// Start Filesystem ///////////////////////////////////////// 51 | void startFilesystem() { 52 | if (!LittleFS.begin()) { 53 | Serial.println("LittleFS Mount Failed"); 54 | return; 55 | } 56 | else { 57 | File root = FILESYSTEM.open("/", "r"); 58 | File file = root.openNextFile(); 59 | while (file) { 60 | const char* fileName = file.name(); 61 | size_t fileSize = file.size(); 62 | Serial.printf("FS File: %s, size: %lu\n", fileName, (long unsigned)fileSize); 63 | file = root.openNextFile(); 64 | } 65 | Serial.println(); 66 | } 67 | } 68 | 69 | 70 | //////////////////////////////// Configure and start local webserver ///////////////////////////////////////// 71 | 72 | /* This is the webpage used to authorize the application (OAuth2.0) */ 73 | #include "gaconfig_htm.h" 74 | 75 | /* Handle /config webpage request */ 76 | void handleConfigPage() { 77 | WebServerClass* webRequest = myWebServer.getRequest(); 78 | webRequest->sendHeader(PSTR("Content-Encoding"), "gzip"); 79 | webRequest->send_P(200, "text/html", AUTHPAGE_HTML, AUTHPAGE_HTML_SIZE); 80 | } 81 | 82 | /* Start local webserver */ 83 | void configureWebServer() { 84 | // Try to connect to flash stored SSID, start AP if fails after timeout 85 | IPAddress myIP = myWebServer.startWiFi(10000, "ESP_AP", "123456789" ); 86 | 87 | // Add 2 buttons for ESP restart and ESP Google authorization page 88 | myWebServer.addOption(FILESYSTEM, "raw-html-button", button_html); 89 | 90 | String infoStr = String(info_html); 91 | infoStr.replace("SETUP_PAGE__PLACEHOLDER", hostname); 92 | myWebServer.addOption(FILESYSTEM, "raw-html-info", infoStr); 93 | myWebServer.addHandler("/config", handleConfigPage); 94 | 95 | // Start webserver 96 | if (myWebServer.begin()) { 97 | Serial.print(F("ESP Web Server started on IP Address: ")); 98 | Serial.println(myIP); 99 | Serial.println(F("Open /setup page to configure optional parameters")); 100 | Serial.println(F("Open /edit page to view and edit files")); 101 | MDNS.begin(hostname); 102 | } 103 | } 104 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 105 | 106 | 107 | void setup() { 108 | Serial.begin(115200); 109 | Serial.println(); 110 | 111 | /* Set Google API web server SSL certificate and NTP timezone */ 112 | #ifdef ESP8266 113 | client.setSession(&session); 114 | client.setTrustAnchors(&certificate); 115 | client.setBufferSizes(1024, 1024); 116 | WiFi.hostname(hostname); 117 | configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); 118 | #elif defined(ESP32) 119 | client.setCACert(google_cert); 120 | WiFi.setHostname(hostname); 121 | configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); 122 | #endif 123 | 124 | /* Get updated local time from NTP */ 125 | getUpdatedtime(10000); 126 | 127 | /* FILESYSTEM init and print list of file*/ 128 | startFilesystem(); 129 | 130 | /* 131 | * Configure the local web server using the esp-fs-webserver library. 132 | * This will also handle WiFi connection, the Captive Portal, and the included WiFiManager. 133 | * The web server can be extended with custom options or web pages for other purposes. 134 | * Check the examples included with the library at: https://github.com/cotestatnt/esp-fs-webserver 135 | */ 136 | configureWebServer(); 137 | 138 | /* Check if application is authorized for selected scope */ 139 | if (myAuth.begin(client_id, client_secret, scopes, api_key, redirect_uri)) { 140 | if (myAuth.getState() == GoogleOAuth2::GOT_TOKEN) { 141 | /* Application authorized, nothing else to do */ 142 | Serial.print(success_message); 143 | } 144 | else { 145 | /* Application not authorized, check your credentials in config.h and perform again authorization procedure */ 146 | Serial.print(warning_message); 147 | } 148 | } 149 | 150 | } 151 | 152 | void loop() { 153 | 154 | if (!myAuth.isAuthorized()) { 155 | /* 156 | * If not authorized run webserver to handle /config webpage requests. 157 | * For debug purpose, you would leave the webserver run also after authorization successfully 158 | */ 159 | myWebServer.run(); 160 | #ifdef ESP8266 161 | MDNS.update(); 162 | #endif 163 | } 164 | } -------------------------------------------------------------------------------- /examples/AuthorizeOnly/config.h: -------------------------------------------------------------------------------- 1 | #define HOSTNAME "esp2sheet" // Setting hostname, you can access to http://HOSTNAME.local instead fixed ip address 2 | 3 | // Google API OAuth2.0 client setup default values (you can change later with setup webpage) 4 | const char* client_id = "490067847793-7gi0i59b45a79a0uq2k435iklm18s33c.apps.googleusercontent.com"; 5 | const char* client_secret = "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"; 6 | const char* api_key = "AIzaSyDFTFbAZlIltVEwq_mePE3gEYd5tQOdszY"; 7 | const char* scopes = "https://www.googleapis.com/auth/drive.file " 8 | "https://www.googleapis.com/auth/spreadsheets "; 9 | 10 | /* 11 | * You can use this redirect_uri if you don't have your own. 12 | * This is a node.js server side application running on Heroku platform 13 | * With Heroku CLI you can clone the repo https://git.heroku.com/arduino-google-api.git 14 | * in order to be able to edit your own custom redirect page. 15 | */ 16 | const char* redirect_uri = "https://arduino-google-api.herokuapp.com"; 17 | 18 | 19 | const char button_html[] = R"EOF( 20 |
21 | )EOF"; 22 | 23 | const char info_html[] = R"EOF( 24 |
Save options if needed, then insert WiFi credentials and connect to SSID.
25 | Once connected to internet, your device need to be authorized from Google in order to use scoped API.
26 | If you are still connected to local ESP Access Point, disconnect and reload webpage

http://SETUP_PAGE__PLACEHOLDER.local

27 | then click on button Authorize ESP to start Google OAuth2.0 authentication workflow

28 | )EOF"; -------------------------------------------------------------------------------- /examples/Gmail/Gmail.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // https://github.com/cotestatnt/esp-fs-webserver 4 | 5 | // Timezone definition to obtain the correct time from the NTP server 6 | #define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" 7 | struct tm Time; 8 | 9 | // Add this scopes to your project in order to be able to handle Gmail API 10 | // https://mail.google.com/ https://www.googleapis.com/auth/gmail.modify 11 | 12 | #include 13 | #include 14 | #define FILESYSTEM LittleFS 15 | 16 | 17 | /* The webserver it's needed only the first time in order to do OAuth2.0 authorizing workflow */ 18 | 19 | #ifdef ESP8266 20 | ESP8266WebServer server(80); 21 | WiFiClientSecure client; 22 | Session session; 23 | X509List certificate(google_cert); 24 | #elif defined(ESP32) 25 | 26 | WiFiClientSecure client; 27 | WebServer server; 28 | #endif 29 | 30 | /* The webserver it's needed only the first time in order to do OAuth2.0 authorizing workflow */ 31 | FSWebServer myWebServer(FILESYSTEM, server); 32 | 33 | 34 | // GmailList mailList; 35 | // GoogleGmailAPI email(FILESYSTEM, client, mailList); 36 | // FSWebServer myWebServer(FILESYSTEM, server); 37 | bool runWebServer = true; 38 | bool authorized = false; 39 | 40 | 41 | /* The instance of library that will handle authorization token renew */ 42 | GoogleOAuth2 myAuth(FILESYSTEM, client); 43 | 44 | GmailList mailList; 45 | GoogleGmailAPI email(&myAuth, &mailList); 46 | 47 | const char* hostname = "espGmailer"; 48 | 49 | #include "config.h" 50 | // This is the webpage used to authorize the application (OAuth2.0) 51 | #include "gaconfig_htm.h" 52 | void handleConfigPage() { 53 | WebServerClass* webRequest = myWebServer.getRequest(); 54 | webRequest->sendHeader(PSTR("Content-Encoding"), "gzip"); 55 | webRequest->send_P(200, "text/html", AUTHPAGE_HTML, AUTHPAGE_HTML_SIZE); 56 | } 57 | 58 | //////////////////////////////// NTP Time ///////////////////////////////////////// 59 | void getUpdatedtime(const uint32_t timeout) 60 | { 61 | uint32_t start = millis(); 62 | do 63 | { 64 | time_t now = time(nullptr); 65 | Time = *localtime(&now); 66 | delay(1); 67 | } while (millis() - start < timeout && Time.tm_year <= (1970 - 1900)); 68 | } 69 | 70 | //////////////////////////////// Start Filesystem ///////////////////////////////////////// 71 | void startFilesystem() { 72 | if (!LittleFS.begin()) { 73 | Serial.println("LittleFS Mount Failed"); 74 | return; 75 | } 76 | else { 77 | File root = FILESYSTEM.open("/", "r"); 78 | File file = root.openNextFile(); 79 | while (file) { 80 | const char* fileName = file.name(); 81 | size_t fileSize = file.size(); 82 | Serial.printf("FS File: %s, size: %lu\n", fileName, (long unsigned)fileSize); 83 | file = root.openNextFile(); 84 | } 85 | Serial.println(); 86 | } 87 | } 88 | 89 | //////////////////////////////// Configure and start local webserver ///////////////////////////////////////// 90 | void configureWebServer() { 91 | // Try to connect to flash stored SSID, start AP if fails after timeout 92 | IPAddress myIP = myWebServer.startWiFi(20000, "ESP_AP", "123456789" ); 93 | 94 | // Add 2 buttons for ESP restart and ESP Google authorization page 95 | myWebServer.addOption(FILESYSTEM, "raw-html-button", button_html); 96 | 97 | String infoStr = String(info_html); 98 | infoStr.replace("SETUP_PAGE__PLACEHOLDER", hostname); 99 | myWebServer.addOption("raw-html-info", infoStr); 100 | myWebServer.addHandler("/config", handleConfigPage); 101 | 102 | // Start webserver 103 | if (myWebServer.begin()) { 104 | Serial.print(F("ESP Web Server started on IP Address: ")); 105 | Serial.println(myIP); 106 | Serial.println(F("Open /setup page to configure optional parameters")); 107 | Serial.println(F("Open /edit page to view and edit files")); 108 | MDNS.begin(hostname); 109 | } 110 | } 111 | 112 | 113 | //////////////////////////////// Chech GMail API configuration ///////////////////////////////////////// 114 | bool configEmailer() 115 | { 116 | if (WiFi.isConnected()) 117 | { 118 | // Begin Google API handling (to store tokens and configuration, filesystem must be mounted before) 119 | if (myAuth.begin(client_id, client_secret, scopes, api_key, redirect_uri)) 120 | { 121 | // Authorization OK when we have a valid token 122 | if (myAuth.getState() == GoogleOAuth2::GOT_TOKEN) 123 | { 124 | Serial.print(F("\n\n-------------------------------------------------------------------------------")); 125 | Serial.print(F("\nYour application has the credentials to use the google API in the selected scope\n")); 126 | Serial.print(F("\n---------------------------------------------------------------------------------\n")); 127 | authorized = true; 128 | 129 | // myGmail.getMailList("cotestatnt@yahoo.com", true, 10); // Get last 10 unread messages sent from provided address 130 | email.getMailList(nullptr, true, 10); // Get last 10 unread messages 131 | Serial.println(F("Unreaded email: ")); 132 | mailList.printList(); 133 | 134 | //////////////////////////////// Send Test email /////////////////////////////////////////// 135 | email.sendEmail("cotestatnt@yahoo.com", "Ciao Tolentino!", "Hello world from Google API Client"); 136 | } 137 | } 138 | 139 | if (myAuth.getState() == GoogleOAuth2::INVALID) 140 | { 141 | Serial.print(warning_message); 142 | runWebServer = true; 143 | return false; 144 | } 145 | } 146 | return false; 147 | } 148 | 149 | 150 | void setup() 151 | { 152 | Serial.begin(115200); 153 | 154 | // FILESYSTEM init and load optins (ssid, password, etc etc) 155 | startFilesystem(); 156 | Serial.println(); 157 | 158 | // Set Google API certificate 159 | #ifdef ESP8266 160 | client.setSession(&session); 161 | client.setTrustAnchors(&certificate); 162 | client.setBufferSizes(1024, 1024); 163 | WiFi.hostname(hostname); 164 | configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); 165 | #elif defined(ESP32) 166 | client.setCACert(google_cert); 167 | WiFi.setHostname(hostname); 168 | configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); 169 | #endif 170 | configureWebServer(); 171 | configEmailer(); 172 | 173 | 174 | // Sync with NTP timeserver 175 | getUpdatedtime(5000); 176 | char _time[30]; 177 | strftime(_time, sizeof(_time), "%d/%m/%Y %H:%M:%S", &Time); 178 | Serial.println(_time); 179 | Serial.readString(); 180 | } 181 | 182 | void loop() 183 | { 184 | if (runWebServer || WiFi.status() != WL_CONNECTED) 185 | { 186 | myWebServer.run(); 187 | #ifdef ESP8266 188 | MDNS.update(); 189 | #endif 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /examples/Gmail/config.h: -------------------------------------------------------------------------------- 1 | // Timezone definition to obtain the correct time from the NTP server 2 | #define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" 3 | #define FILESYSTEM LittleFS 4 | 5 | // Google API OAuth2.0 client setup default values (you can change later with setup webpage) 6 | const char* client_id = "408231038603-f9g6btf4ip5ge3guv944q01qvoa2srhf.apps.googleusercontent.com"; 7 | const char* client_secret = "jb7XS8CMqgSsMUuldZm3LfJG"; 8 | const char* api_key = "AIzaSyB-kUJQOcFya2Ls7qMlofObXhsECs2e3i0"; 9 | const char* scopes = "https://www.googleapis.com/auth/drive.file " 10 | "https://www.googleapis.com/auth/spreadsheets "; 11 | 12 | /* 13 | * You can use this redirect_uri if you don't have your own. 14 | * This is a node.js server side application running on Heroku platform 15 | * With Heroku CLI you can clone the repo https://git.heroku.com/arduino-google-api.git 16 | * in order to be able to edit your own custom redirect page. 17 | */ 18 | const char* redirect_uri = "https://arduino-google-api.herokuapp.com"; 19 | 20 | static const char button_html[] PROGMEM = R"EOF( 21 |
22 | )EOF"; 23 | 24 | static const char info_html[] PROGMEM = R"EOF( 25 |
Save options if needed, then insert WiFi credentials and connect to SSID.
26 | Once connected to internet, your device need to be authorized from Google in order to write Sheets.
27 | If you are still connected to local ESP Access Point, disconnect and reload webpage

http://SETUP_PAGE__PLACEHOLDER.local

28 | then click on button Authorize ESP to start Google OAuth2.0 authentication workflow

29 | )EOF"; 30 | -------------------------------------------------------------------------------- /examples/GoogleCalendar/GoogleCalendar.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // https://github.com/cotestatnt/esp-fs-webserver 4 | 5 | // Timezone definition to obtain the correct time from the NTP server 6 | #define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" 7 | struct tm Time; 8 | 9 | // Filesystem will be used to store access credentials and custom options 10 | #include 11 | #include 12 | #define FILESYSTEM LittleFS 13 | 14 | #include 15 | #ifdef ESP8266 16 | #include 17 | using WebServerClass = ESP8266WebServer; 18 | Session session; 19 | X509List certificate(google_cert); 20 | #elif defined(ESP32) 21 | #include 22 | using WebServerClass = WebServer; 23 | #endif 24 | 25 | #include "config.h" 26 | 27 | /* The webserver it's needed only the first time in order to do OAuth2.0 authorizing workflow */ 28 | WebServerClass server; 29 | FSWebServer myWebServer(FILESYSTEM, server); 30 | 31 | /* The web client used from library */ 32 | WiFiClientSecure client; 33 | 34 | /* The instance of library that will handle authorization token renew */ 35 | GoogleOAuth2 myAuth(FILESYSTEM, client); 36 | EventList eventList; 37 | GoogleCalendarAPI calendar(myAuth, eventList); 38 | 39 | const char* hostname = "esp2calendar"; 40 | String calendarId; 41 | 42 | //////////////////////////////// Start Filesystem ///////////////////////////////////////// 43 | void startFilesystem() { 44 | if (!LittleFS.begin()) { 45 | Serial.println("LittleFS Mount Failed"); 46 | return; 47 | } 48 | else { 49 | File root = FILESYSTEM.open("/", "r"); 50 | File file = root.openNextFile(); 51 | while (file) { 52 | const char* fileName = file.name(); 53 | size_t fileSize = file.size(); 54 | Serial.printf("FS File: %s, size: %lu\n", fileName, (long unsigned)fileSize); 55 | file = root.openNextFile(); 56 | } 57 | Serial.println(); 58 | } 59 | } 60 | 61 | //////////////////////////////// Configure and start local webserver ///////////////////////////////////////// 62 | 63 | /* This is the webpage used to authorize the application (OAuth2.0) */ 64 | #include "gaconfig_htm.h" 65 | 66 | /* Handle /config webpage request */ 67 | void handleConfigPage() { 68 | WebServerClass* webRequest = myWebServer.getRequest(); 69 | webRequest->sendHeader(PSTR("Content-Encoding"), "gzip"); 70 | webRequest->send_P(200, "text/html", AUTHPAGE_HTML, AUTHPAGE_HTML_SIZE); 71 | } 72 | 73 | /* Start local webserver */ 74 | void configureWebServer() { 75 | // Try to connect to flash stored SSID, start AP if fails after timeout 76 | IPAddress myIP = myWebServer.startWiFi(20000, "ESP_AP", "123456789" ); 77 | 78 | // Add 2 buttons for ESP restart and ESP Google authorization page 79 | myWebServer.addOption(FILESYSTEM, "raw-html-button", button_html); 80 | 81 | String infoStr = String(info_html); 82 | infoStr.replace("SETUP_PAGE__PLACEHOLDER", hostname); 83 | myWebServer.addOption(FILESYSTEM, "raw-html-info", infoStr); 84 | myWebServer.addHandler("/config", handleConfigPage); 85 | 86 | // Start webserver 87 | if (myWebServer.begin()) { 88 | Serial.print(F("ESP Web Server started on IP Address: ")); 89 | Serial.println(myIP); 90 | Serial.println(F("Open /setup page to configure optional parameters")); 91 | Serial.println(F("Open /edit page to view and edit files")); 92 | MDNS.begin(hostname); 93 | } 94 | } 95 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 96 | 97 | 98 | void setup() { 99 | Serial.begin(115200); 100 | Serial.println(); 101 | 102 | /* FILESYSTEM init and print list of file*/ 103 | startFilesystem(); 104 | 105 | /* Set Google API web server SSL certificate and NTP timezone */ 106 | #ifdef ESP8266 107 | client.setSession(&session); 108 | client.setTrustAnchors(&certificate); 109 | client.setBufferSizes(1024, 1024); 110 | WiFi.hostname(hostname); 111 | configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); 112 | #elif defined(ESP32) 113 | client.setCACert(google_cert); 114 | WiFi.setHostname(hostname); 115 | configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); 116 | #endif 117 | 118 | /* 119 | * Configure the local web server using the esp-fs-webserver library. 120 | * This will also handle WiFi connection, the Captive Portal, and the included WiFiManager. 121 | * The web server can be extended with custom options or web pages for other purposes. 122 | * Check the examples included with the library at: https://github.com/cotestatnt/esp-fs-webserver 123 | */ 124 | configureWebServer(); 125 | 126 | /* Get updated local time from NTP */ 127 | getLocalTime(&Time, 10000); 128 | char str[32]; 129 | strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%S%z", &Time); 130 | Serial.println(str); 131 | 132 | /* Check if application is authorized for selected scope */ 133 | if (myAuth.begin(client_id, client_secret, scopes, api_key, redirect_uri)) { 134 | /* Application authorized, nothing else to do */ 135 | Serial.print(success_message); 136 | 137 | /* Check if a calendar is present or create (default calendar ID is equal to account gmail address) */ 138 | calendarId = calendar.checkCalendar("ESP Test Calendar", true, "Europe/Rome"); 139 | Serial.printf("Calendar id: %s\n", calendarId.c_str()); 140 | 141 | /* get event list starting from now */ 142 | calendar.getEventList(calendarId.c_str()); 143 | calendar.prinEventList(); 144 | 145 | /* Create a new event using a simple text sentence */ 146 | //String eventId = calendar.quickAddEvent(calendarId.c_str(), "Simple Test Event 10/06/2022 15:00 18:00"); 147 | //Serial.printf("New event added, id: %s\n", eventId.c_str()); 148 | 149 | //delay(5000); 150 | //calendar.deleteEvent(calendarId, eventId); 151 | 152 | /* 153 | * Create a new event passing all parameters. 154 | * You can create a time_t variable e.g. with class utility "getEpochTime()" 155 | * The default RRULE is for a single event with no recurrency (you can omit last 2 params) 156 | */ 157 | time_t start = calendar.getEpochTime(2022, 06, 14, 17, 0); 158 | time_t end = calendar.getEpochTime(2022, 06, 14, 20, 0); 159 | String eventId = calendar.addEvent(calendarId.c_str(), "Test event", start, end, GoogleCalendarAPI::DAILY, 3); 160 | 161 | /* As alternative you can use directly a RRULE sentence or a list of rules. Ex: "RRULE:FREQ=DAILY;COUNT=3" */ 162 | // String eventId = calendar.addEvent(calendarId.c_str(), "Test event", start, end, "RRULE:FREQ=DAILY;COUNT=3"); 163 | Serial.printf("New event added, id: %s\n", eventId.c_str()); 164 | } 165 | else { 166 | /* Application not authorized, check your credentials in config.h and perform again authorization procedure */ 167 | Serial.print(warning_message); 168 | } 169 | 170 | } 171 | 172 | void loop() { 173 | 174 | if (/*!myAuth.isAuthorized()*/true) { 175 | /* 176 | * If not authorized run webserver to handle /config webpage requests. 177 | * For debug purpose, you would leave the webserver run also after authorization successfully 178 | */ 179 | myWebServer.run(); 180 | #ifdef ESP8266 181 | MDNS.update(); 182 | #endif 183 | } 184 | 185 | /* check if an event occurs in the next hour */ 186 | static uint32_t checkTime; 187 | if (millis() -checkTime > 30000) { 188 | checkTime = millis(); 189 | time_t now = time(nullptr); 190 | int evCount = calendar.getEventList(calendarId.c_str(), now, now + 3600); 191 | for (int i=0; i < evCount; i++) { 192 | 193 | if (calendar.eventInProgress(i)) { 194 | EventList::EventItem* event = calendar.getEvent(i); 195 | Serial.printf("The event \"%s\" is actually in progress\n", event->summary.c_str()); 196 | } 197 | 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /examples/GoogleCalendar/config.h: -------------------------------------------------------------------------------- 1 | // Google API OAuth2.0 client setup default values (you can change later with setup webpage) 2 | const char* client_id = "xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com"; 3 | const char* client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxx"; 4 | const char* api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxx"; 5 | const char* scopes = "https://www.googleapis.com/auth/drive.file " 6 | "https://www.googleapis.com/auth/spreadsheets " 7 | "https://mail.google.com/ https://www.googleapis.com/auth/calendar "; 8 | 9 | 10 | /* 11 | * You can use this redirect_uri if you don't have your own. 12 | * This is a node.js server side application running on Heroku platform 13 | * With Heroku CLI you can clone the repo https://git.heroku.com/arduino-google-api.git 14 | * in order to be able to edit your own custom redirect page. 15 | */ 16 | const char* redirect_uri = "https://arduino-google-api.herokuapp.com"; 17 | 18 | 19 | const char button_html[] = R"EOF( 20 |
21 | )EOF"; 22 | 23 | const char info_html[] = R"EOF( 24 |
Save options if needed, then insert WiFi credentials and connect to SSID.
25 | Once connected to internet, your device need to be authorized from Google in order to use scoped API.
26 | If you are still connected to local ESP Access Point, disconnect and reload webpage

http://SETUP_PAGE__PLACEHOLDER.local

27 | then click on button Authorize ESP to start Google OAuth2.0 authentication workflow

28 | )EOF"; -------------------------------------------------------------------------------- /examples/GoogleDrive/config.h: -------------------------------------------------------------------------------- 1 | // Timezone definition to obtain the correct time from the NTP server 2 | #define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" 3 | #define FILESYSTEM LittleFS 4 | 5 | #define HOSTNAME "esp2drive" // Setting hostname, you can access to http://HOSTNAME.local instead fixed ip address 6 | #define FOLDER_NAME "myFolder" 7 | #define S_FILENAME "myTestData" 8 | 9 | // Google API OAuth2.0 client setup default values (you can change later with setup webpage) 10 | const char* client_id = "408231038603-f9g6btf4ip5ge3guv944q01qvoa2srhf.apps.googleusercontent.com"; 11 | const char* client_secret = "jb7XS8CMqgSsMUuldZm3LfJG"; 12 | const char* api_key = "AIzaSyB-kUJQOcFya2Ls7qMlofObXhsECs2e3i0"; 13 | const char* scopes = "https://www.googleapis.com/auth/drive.file " 14 | "https://www.googleapis.com/auth/spreadsheets "; 15 | 16 | /* 17 | * You can use this redirect_uri if you don't have your own. 18 | * This is a node.js server side application running on Heroku platform 19 | * With Heroku CLI you can clone the repo https://git.heroku.com/arduino-google-api.git 20 | * in order to be able to edit your own custom redirect page. 21 | */ 22 | const char* redirect_uri = "https://arduino-google-api.herokuapp.com"; 23 | 24 | static const char button_html[] PROGMEM = R"EOF( 25 |
26 | )EOF"; 27 | 28 | static const char info_html[] PROGMEM = R"EOF( 29 |
Save options if needed, then insert WiFi credentials and connect to SSID.
30 | Once connected to internet, your device need to be authorized from Google in order to write Sheets.
31 | If you are still connected to local ESP Access Point, disconnect and reload webpage

http://SETUP_PAGE__PLACEHOLDER.local

32 | then click on button Authorize ESP to start Google OAuth2.0 authentication workflow

33 | )EOF"; 34 | -------------------------------------------------------------------------------- /examples/GoogleDrive_ESP32_Task/config.h: -------------------------------------------------------------------------------- 1 | // Google API OAuth2.0 client setup default values (you can change later with setup webpage) 2 | const char* client_id = "490067847793-7gi0i59b45a79a0uq2k435iklm18s33c.apps.googleusercontent.com"; 3 | const char* client_secret = "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"; 4 | const char* api_key = "AIzaSyDFTFbAZlIltVEwq_mePE3gEYd5tQOdszY"; 5 | const char* scopes = "https://www.googleapis.com/auth/drive.file " 6 | "https://www.googleapis.com/auth/spreadsheets "; 7 | 8 | 9 | /* 10 | * You can use this redirect_uri if you don't have your own. 11 | * This is a node.js server side application running on Heroku platform 12 | * With Heroku CLI you can clone the repo https://git.heroku.com/arduino-google-api.git 13 | * in order to be able to edit your own custom redirect page. 14 | */ 15 | const char* redirect_uri = "https://arduino-google-api.herokuapp.com"; 16 | 17 | 18 | const char button_html[] = R"EOF( 19 |
20 | )EOF"; 21 | 22 | const char info_html[] = R"EOF( 23 |
Save options if needed, then insert WiFi credentials and connect to SSID.
24 | Once connected to internet, your device need to be authorized from Google in order to use scoped API.
25 | If you are still connected to local ESP Access Point, disconnect and reload webpage

http://SETUP_PAGE__PLACEHOLDER.local

26 | then click on button Authorize ESP to start Google OAuth2.0 authentication workflow

27 | )EOF"; -------------------------------------------------------------------------------- /examples/GoogleDrive_logdata/config.h: -------------------------------------------------------------------------------- 1 | // Timezone definition to obtain the correct time from the NTP server 2 | #define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" 3 | #define FILESYSTEM LittleFS 4 | 5 | #define HOSTNAME "esp2drive" // Setting hostname, you can access to http://HOSTNAME.local instead fixed ip address 6 | #define FOLDER_NAME "myFolder" 7 | #define S_FILENAME "myTestData" 8 | 9 | // Google API OAuth2.0 client setup default values (you can change later with setup webpage) 10 | const char* client_id = "408231038603-f9g6btf4ip5ge3guv944q01qvoa2srhf.apps.googleusercontent.com"; 11 | const char* client_secret = "jb7XS8CMqgSsMUuldZm3LfJG"; 12 | const char* api_key = "AIzaSyB-kUJQOcFya2Ls7qMlofObXhsECs2e3i0"; 13 | const char* scopes = "https://www.googleapis.com/auth/drive.file " 14 | "https://www.googleapis.com/auth/spreadsheets "; 15 | 16 | 17 | /* 18 | * You can use this redirect_uri if you don't have your own. 19 | * This is a node.js server side application running on Heroku platform 20 | * With Heroku CLI you can clone the repo https://git.heroku.com/arduino-google-api.git 21 | * in order to be able to edit your own custom redirect page. 22 | */ 23 | const char* redirect_uri = "https://arduino-google-api.herokuapp.com"; 24 | 25 | 26 | const char button_html[] = R"EOF( 27 |
28 | )EOF"; 29 | 30 | const char info_html[] = R"EOF( 31 |
Save options if needed, then insert WiFi credentials and connect to SSID.
32 | Once connected to internet, your device need to be authorized from Google in order to use scoped API.
33 | If you are still connected to local ESP Access Point, disconnect and reload webpage

http://SETUP_PAGE__PLACEHOLDER.local

34 | then click on button Authorize ESP to start Google OAuth2.0 authentication workflow

35 | )EOF"; -------------------------------------------------------------------------------- /examples/GoogleSheet/GoogleSheet.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // https://github.com/cotestatnt/esp-fs-webserver 4 | 5 | // Timezone definition to obtain the correct time from the NTP server 6 | #define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" 7 | struct tm Time; 8 | 9 | // Filesystem will be used to store access credentials and custom options 10 | #include 11 | #include 12 | #define FILESYSTEM LittleFS 13 | 14 | #include 15 | #ifdef ESP8266 16 | #include 17 | using WebServerClass = ESP8266WebServer; 18 | Session session; 19 | X509List certificate(google_cert); 20 | #elif defined(ESP32) 21 | #include 22 | using WebServerClass = WebServer; 23 | #endif 24 | 25 | #include "config.h" 26 | 27 | /* The webserver it's needed only the first time in order to do OAuth2.0 authorizing workflow */ 28 | WebServerClass server; 29 | FSWebServer myWebServer(FILESYSTEM, server); 30 | 31 | /* The web client used from library */ 32 | WiFiClientSecure client; 33 | 34 | /* The instance of library that will handle authorization token renew */ 35 | GoogleOAuth2 myAuth(FILESYSTEM, client); 36 | 37 | /* The instance of library that will handle Sheet API. 38 | * GoogleFilelist object is optional, but can take a local reference to remote IDs 39 | * in order to speed up file operations like searching or similar. 40 | */ 41 | GoogleSheetAPI mySheet(&myAuth); 42 | 43 | const char *hostname = "esp2sheet"; 44 | 45 | String spreadSheetId; 46 | String folderName = "SheetFolder"; 47 | String spreadSheetName = "mySheet"; 48 | String sheetName = "myData"; 49 | unsigned long updateInterval = 30 * 1000; // Add row to sheet every x seconds 50 | 51 | const char *formulaExample = "\"=IF(ISNUMBER(B:B); B:B - C:C;)\""; 52 | 53 | //////////////////////////////// NTP Time ///////////////////////////////////////// 54 | void getUpdatedtime(const uint32_t timeout) 55 | { 56 | uint32_t start = millis(); 57 | do 58 | { 59 | time_t now = time(nullptr); 60 | Time = *localtime(&now); 61 | delay(1); 62 | } while (millis() - start < timeout && Time.tm_year <= (1970 - 1900)); 63 | } 64 | 65 | //////////////////////////////// Start Filesystem ///////////////////////////////////////// 66 | void startFilesystem() 67 | { 68 | if (!LittleFS.begin()) 69 | { 70 | Serial.println("LittleFS Mount Failed"); 71 | return; 72 | } 73 | else 74 | { 75 | File root = FILESYSTEM.open("/", "r"); 76 | File file = root.openNextFile(); 77 | while (file) 78 | { 79 | const char *fileName = file.name(); 80 | size_t fileSize = file.size(); 81 | Serial.printf("FS File: %s, size: %lu\n", fileName, (long unsigned)fileSize); 82 | file = root.openNextFile(); 83 | } 84 | Serial.println(); 85 | } 86 | } 87 | 88 | //////////////////////////////// Configure and start local webserver ///////////////////////////////////////// 89 | 90 | /* This is the webpage used to authorize the application (OAuth2.0) */ 91 | #include "gaconfig_htm.h" 92 | 93 | /* Handle /config webpage request */ 94 | void handleConfigPage() 95 | { 96 | WebServerClass *webRequest = myWebServer.getRequest(); 97 | webRequest->sendHeader(PSTR("Content-Encoding"), "gzip"); 98 | webRequest->send_P(200, "text/html", AUTHPAGE_HTML, AUTHPAGE_HTML_SIZE); 99 | } 100 | 101 | /* Start local webserver */ 102 | void configureWebServer() 103 | { 104 | // Try to connect to flash stored SSID, start AP if fails after timeout 105 | IPAddress myIP = myWebServer.startWiFi(10000, "ESP_AP", "123456789"); 106 | 107 | // Add 2 buttons for ESP restart and ESP Google authorization page 108 | myWebServer.addOption(FILESYSTEM, "raw-html-button", button_html); 109 | 110 | String infoStr = String(info_html); 111 | infoStr.replace("SETUP_PAGE__PLACEHOLDER", hostname); 112 | myWebServer.addOption(FILESYSTEM, "raw-html-info", infoStr); 113 | myWebServer.addHandler("/config", handleConfigPage); 114 | 115 | // Start webserver 116 | if (myWebServer.begin()) 117 | { 118 | Serial.print(F("ESP Web Server started on IP Address: ")); 119 | Serial.println(myIP); 120 | Serial.println(F("Open /setup page to configure optional parameters")); 121 | Serial.println(F("Open /edit page to view and edit files")); 122 | MDNS.begin(hostname); 123 | } 124 | } 125 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 126 | 127 | //////////////////////////////// Append new row of data to sheet ///////////////////////////////////////// 128 | void appendData() 129 | { 130 | static uint32_t timeUpdate = 0; 131 | 132 | if (millis() - timeUpdate > updateInterval) 133 | { 134 | // Append a new row to the sheet 135 | timeUpdate = millis(); 136 | #ifdef ESP32 137 | size_t free; 138 | size_t max; 139 | free = heap_caps_get_free_size(0); 140 | max = heap_caps_get_largest_free_block(0); 141 | #elif defined(ESP8266) 142 | uint32_t free; 143 | uint16_t max; 144 | ESP.getHeapStats(&free, &max, nullptr); 145 | #endif 146 | time_t rawtime = time(nullptr); 147 | Time = *localtime(&rawtime); 148 | char buffer[30]; 149 | strftime(buffer, sizeof(buffer), "\"%d/%m/%Y %H:%M:%S\"", &Time); 150 | char row[200]; 151 | snprintf(row, sizeof(row), "[%s, %d, %d, %s]", buffer, free, max, formulaExample); 152 | String range = sheetName; 153 | range += "!A1"; 154 | if (mySheet.appendRowToSheet(spreadSheetId.c_str(), range.c_str(), row)) 155 | Serial.printf("New row appended to %s::%s succesfully\n", spreadSheetName.c_str(), sheetName.c_str()); 156 | else 157 | Serial.println("Failed to append data to Sheet"); 158 | } 159 | } 160 | 161 | void setup() 162 | { 163 | Serial.begin(115200); 164 | Serial.println(); 165 | 166 | /* Set Google API web server SSL certificate and NTP timezone */ 167 | #ifdef ESP8266 168 | client.setSession(&session); 169 | client.setTrustAnchors(&certificate); 170 | client.setBufferSizes(1024, 1024); 171 | WiFi.hostname(hostname); 172 | configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); 173 | #elif defined(ESP32) 174 | client.setCACert(google_cert); 175 | WiFi.setHostname(hostname); 176 | configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); 177 | #endif 178 | 179 | /* Get updated local time from NTP */ 180 | getUpdatedtime(10000); 181 | 182 | /* FILESYSTEM init and print list of file*/ 183 | startFilesystem(); 184 | 185 | /* 186 | * Configure local web server: with esp-fs-webserver library, 187 | * this will handle also the WiFi connection, the Captive Portal and included WiFiManager. 188 | * The webserver can be also extended with custom options or webpages for other purposes. 189 | * Check the examples included with library https://github.com/cotestatnt/esp-fs-webserver 190 | */ 191 | configureWebServer(); 192 | 193 | /* Check if application is authorized for selected scope */ 194 | if (myAuth.begin(client_id, client_secret, scopes, api_key, redirect_uri)) 195 | { 196 | if (myAuth.getState() == GoogleOAuth2::GOT_TOKEN) 197 | { 198 | /* Application authorized */ 199 | Serial.print(success_message); 200 | 201 | // Check if the spreadsheet is already created and inside provided folder (create if not) 202 | spreadSheetId = mySheet.isSpreadSheet(spreadSheetName.c_str(), folderName.c_str(), true); 203 | if (spreadSheetId.length() >= MIN_ID_LEN) 204 | { 205 | // A valid Google spreadsheet id founded 206 | Serial.printf("Spreasheet is present, id: %s\n", spreadSheetId.c_str()); 207 | } 208 | else 209 | { 210 | // Create a new spreadsheet if not exist, return the sheet ID (44 random chars) 211 | spreadSheetId = mySheet.newSpreadsheet(spreadSheetName.c_str(), mySheet.getParentId()); 212 | Serial.printf("New Spreasheet created, id: %s\n", spreadSheetId.c_str()); 213 | delay(500); 214 | 215 | ///////// Optional: rename default sheet (id == 0) with provided name //////////// 216 | if (mySheet.setSheetTitle(sheetName.c_str(), spreadSheetId.c_str())) 217 | { 218 | Serial.printf("Sheet title updated to \"%s\" (%s)\n", sheetName.c_str(), spreadSheetId.c_str()); 219 | } 220 | ///////////////////////////////////////////////////////////////////////////////////// 221 | 222 | ///////// Optional: create an additional sheet with provided name //////////// 223 | /* 224 | uint32_t newSheetId = mySheet.newSheet("testSheet", spreadSheetId.c_str()); 225 | if (newSheetId) 226 | Serial.printf("New sheet \"testSheet\" added to spreadsheet, id: %ld\n", newSheetId); 227 | */ 228 | ///////////////////////////////////////////////////////////////////////////////////// 229 | 230 | // Add first header row ['colA', 'colB', 'colC', .... ] 231 | String row = "['Timestamp', 'Max free heap', 'Max block size', 'Difference']"; 232 | String range; 233 | // range += sheetName; 234 | range += "!A1"; 235 | mySheet.appendRowToSheet(spreadSheetId, range, row); 236 | } 237 | } 238 | else 239 | { 240 | /* Application not authorized, check your credentials in config.h and perform again authorization procedure */ 241 | Serial.print(warning_message); 242 | } 243 | } 244 | } 245 | 246 | void loop() 247 | { 248 | 249 | if (!myAuth.isAuthorized()) 250 | { 251 | #ifdef ESP8266 252 | MDNS.update(); 253 | #endif 254 | /* 255 | * If not authorized run webserver to handle /config webpage requests. 256 | * For debug purpose, you would leave the webserver run also after authorization successfully 257 | */ 258 | myWebServer.run(); 259 | } 260 | else 261 | { 262 | // Append new data to Google Sheet 263 | static uint32_t appendTime; 264 | if (millis() - appendTime > 30000) 265 | { 266 | appendTime = millis(); 267 | appendData(); 268 | } 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /examples/GoogleSheet/config.h: -------------------------------------------------------------------------------- 1 | // Timezone definition to obtain the correct time from the NTP server 2 | #define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" 3 | #define FILESYSTEM LittleFS 4 | 5 | #define HOSTNAME "esp2sheet" // Setting hostname, you can access to http://HOSTNAME.local instead fixed ip address 6 | #define FOLDER_NAME "SheetFolder" 7 | #define S_FILENAME "myTestSheet" 8 | #define SHEETNAME "datasource" 9 | 10 | 11 | // Google API OAuth2.0 client setup default values (you can change later with setup webpage) 12 | const char* client_id = "xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com"; 13 | const char* client_secret = "xxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; 14 | const char* api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; 15 | const char* scopes = "https://www.googleapis.com/auth/drive.file " 16 | "https://www.googleapis.com/auth/spreadsheets "; 17 | 18 | /* 19 | * You can use this redirect_uri if you don't have your own. 20 | * This is a node.js server side application running on Heroku platform 21 | * With Heroku CLI you can clone the repo https://git.heroku.com/arduino-google-api.git 22 | * in order to be able to edit your own custom redirect page. 23 | */ 24 | const char* redirect_uri = "https://arduino-google-api.herokuapp.com"; 25 | 26 | static const char button_html[] PROGMEM = R"EOF( 27 |
28 | )EOF"; 29 | 30 | static const char info_html[] PROGMEM = R"EOF( 31 |
Save options if needed, then insert WiFi credentials and connect to SSID.
32 | Once connected to internet, your device need to be authorized from Google in order to write Sheets.
33 | If you are still connected to local ESP Access Point, disconnect and reload webpage

http://SETUP_PAGE__PLACEHOLDER.local

34 | then click on button Authorize ESP to start Google OAuth2.0 authentication workflow

35 | )EOF"; 36 | -------------------------------------------------------------------------------- /extras/feathericons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/extras/feathericons.png -------------------------------------------------------------------------------- /extras/index.htm.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/extras/index.htm.gz -------------------------------------------------------------------------------- /extras/reduce_index.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | # Processing script to optionally reduce filesystem use by miniying, gzipping and preparing index.htm for embedding in code. 4 | # Please see readme.md for more information. 5 | 6 | # Requires xdd which is part of the VIM package 7 | # Requires npm 8 | # sudo apt install npm 9 | # ln -s /usr/bin/nodejs /usr/bin/node 10 | # Requires html-minifier 11 | # sudo npm install html-minifier -g 12 | 13 | html-minifier \ 14 | --case-sensitive \ 15 | --collapse-boolean-attributes \ 16 | --collapse-whitespace \ 17 | --minify-css true \ 18 | --minify-js true \ 19 | --process-conditional-comments \ 20 | --remove-attribute-quotes \ 21 | --remove-comments \ 22 | --remove-empty-attributes \ 23 | --remove-optional-tags \ 24 | --remove-redundant-attributes \ 25 | --remove-script-type-attributes \ 26 | --remove-style-link-type-attributes \ 27 | -o index.htm \ 28 | ../data/edit/index.htm 29 | 30 | if [ $? -ne 0 ] 31 | then 32 | echo "Error minifying index.htm" 33 | exit -1 34 | fi 35 | 36 | if [ -e index.htm.gz ] 37 | then 38 | rm index.htm.gz 39 | fi 40 | 41 | gzip index.htm 42 | if [ $? -ne 0 ] 43 | then 44 | echo "Error gzipping minified index.htm" 45 | exit -1 46 | fi 47 | 48 | echo '// WARNING: Auto-generated file. Please do not modify by hand.' > index_htm.h 49 | echo '// This file is an embeddable version of the gzipped index.htm file.' >> index_htm.h 50 | echo '// To update it, please rerun the `reduce_index.sh` script located in the `extras` subfolder' >> index_htm.h 51 | echo '// then recompile the sketch after each change to the `index.html` file.' >> index_htm.h 52 | xxd -i index.htm.gz >> index_htm.h 53 | if [ $? -ne 0 ] 54 | then 55 | echo "Error creating include file from index.htm.gz" 56 | exit -1 57 | fi 58 | 59 | echo Reduce complete. 60 | 61 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | GoogleAPI KEYWORD1 2 | GoogleFile KEYWORD1 3 | GoogleFilelist KEYWORD1 4 | 5 | 6 | 7 | printConfig KEYWORD2 8 | getState KEYWORD2 9 | printConfig KEYWORD2 10 | 11 | clearConfig KEYWORD2 12 | refreshToken KEYWORD2 13 | getNumFiles KEYWORD2 14 | getFileName KEYWORD2 15 | getFileId KEYWORD2 16 | 17 | searchFile KEYWORD2 18 | uploadFile KEYWORD2 19 | printAppFiles KEYWORD2 20 | createAppFolder KEYWORD2 21 | 22 | access_token KEYWORD3 23 | verification_url KEYWORD3 24 | user_code KEYWORD3 25 | expires_in KEYWORD3 26 | appFolderId KEYWORD3 27 | 28 | 29 | MessageNoData LITERAL1 30 | MessageText LITERAL1 31 | MessageQuery LITERAL1 32 | MessageLocation LITERAL1 33 | KeyboardButtonURL LITERAL1 34 | KeyboardButtonQuery LITERAL1 35 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=GoogleAPI 2 | version=1.0.2 3 | author=Tolentino Cotesta 4 | maintainer=Tolentino Cotesta 5 | sentence=Library for authenticate (OAuth 2.0) your ESP32 and ESP8266 device and use Google Drive, GMail and Sheet API (Calendar will be avalaible soon). 6 | paragraph=OAuth 2.0 for TV and Limited-Input Device Applications or as Web Server Application. 7 | category=Communication 8 | url=https://github.com/cotestatnt/Arduino-Google-API 9 | architectures=esp8266,esp32 10 | depends=ArduinoJson,esp-fs-webserver -------------------------------------------------------------------------------- /php_gauth/auth_code.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/php_gauth/auth_code.txt -------------------------------------------------------------------------------- /php_gauth/endpoint.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | OAuth2.0 endpoint 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 |
21 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /php_gauth/getAuthCode.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | 18 | -------------------------------------------------------------------------------- /php_gauth/smart-air.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/php_gauth/smart-air.png -------------------------------------------------------------------------------- /src/Base64.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE64_WRAPPER_H 2 | #define BASE64_WRAPPER_H 3 | 4 | #include "Arduino.h" 5 | #include 6 | 7 | extern "C" { 8 | #include "libb64/cdecode.h" 9 | #include "libb64/cencode.h" 10 | } 11 | 12 | class Base64 13 | { 14 | public: 15 | /** 16 | * convert input data to base64 17 | * @param data const uint8_t * 18 | * @param length size_t 19 | * @return String 20 | */ 21 | static String encode(const uint8_t * data, size_t length) 22 | { 23 | size_t size = base64_encode_expected_len(length) + 1; 24 | char * buffer = (char *) malloc(size); 25 | if(buffer) { 26 | base64_encodestate _state; 27 | base64_init_encodestate(&_state); 28 | int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state); 29 | len = base64_encode_blockend((buffer + len), &_state); 30 | 31 | String base64 = String(buffer); 32 | free(buffer); 33 | return base64; 34 | } 35 | return String("-FAIL-"); 36 | } 37 | 38 | 39 | /** 40 | * convert input data to base64 41 | * @param text const String& 42 | * @return String 43 | */ 44 | static String encode(const String& text) 45 | { 46 | return Base64::encode((uint8_t *) text.c_str(), text.length()); 47 | } 48 | 49 | 50 | /** 51 | * convert input base64 to plain text 52 | * @param base64 const char* 53 | * @return String 54 | */ 55 | static String decode(const char* base64) 56 | { 57 | int len = strlen(base64); 58 | char plainText[len]; 59 | 60 | base64_decode_chars(base64, len, plainText); 61 | return plainText; 62 | } 63 | 64 | /** 65 | * convert input base64 to plain text 66 | * @param base64 const String& 67 | * @return String 68 | */ 69 | static String decode(const String& base64) 70 | { 71 | return decode(base64.c_str()); 72 | } 73 | 74 | private: 75 | }; 76 | 77 | #endif -------------------------------------------------------------------------------- /src/Const.h: -------------------------------------------------------------------------------- 1 | 2 | #define AUTH_HOST "oauth2.googleapis.com" 3 | #define PORT 443 4 | #define MIN_ID_LEN 33 5 | 6 | static const char google_cert[] PROGMEM = R"EOF( 7 | -----BEGIN CERTIFICATE----- 8 | MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG 9 | A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv 10 | b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw 11 | MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i 12 | YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT 13 | aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ 14 | jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp 15 | xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 16 | 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG 17 | snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ 18 | U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 19 | 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E 20 | BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B 21 | AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz 22 | yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 23 | 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP 24 | AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad 25 | DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME 26 | HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== 27 | -----END CERTIFICATE----- 28 | )EOF"; 29 | 30 | const char warning_message[] PROGMEM = R"EOF( 31 | --------------------------------------------------------------------------------- 32 | Google says that your client is NOT VALID! You have to authorize the application. 33 | For instructions, check the page https://github.com/cotestatnt/Arduino-Google-API 34 | You need to authorize this appplication with configation webpage, then restart. 35 | --------------------------------------------------------------------------------- 36 | )EOF"; 37 | 38 | const char success_message[] PROGMEM = R"EOF( 39 | -------------------------------------------------------------------------------- 40 | Your application has the credentials to use the google API in the selected scope 41 | -------------------------------------------------------------------------------- 42 | )EOF"; -------------------------------------------------------------------------------- /src/GoogleCalendar.cpp: -------------------------------------------------------------------------------- 1 | #include "GoogleCalendar.h" 2 | #include "Base64.h" 3 | 4 | 5 | String GoogleCalendarAPI::parsePayload(const String &payload, const int filter, const char *keyword) 6 | { 7 | #if defined(ESP8266) 8 | DynamicJsonDocument doc(ESP.getMaxFreeBlockSize() - 512); 9 | #elif defined(ESP32) 10 | DynamicJsonDocument doc(ESP.getMaxAllocHeap() - 512); 11 | #else 12 | DynamicJsonDocument doc(payload.length() + 256); 13 | #endif 14 | DeserializationError err = deserializeJson(doc, payload); 15 | if (err) 16 | { 17 | log_error("deserializeJson() failed\n"); 18 | log_error("%s\n", err.c_str()); 19 | return ""; 20 | } 21 | 22 | String result = ""; 23 | switch (filter) 24 | { 25 | case CALENDARS: 26 | if (doc["items"]) 27 | { 28 | JsonArray array = doc["items"].as(); 29 | for (JsonVariant calendar : array) 30 | { 31 | if (calendar["summary"].as().equals(keyword)) { 32 | result = calendar["id"].as(); 33 | m_calendarTimeZone = calendar["timeZone"].as(); 34 | } 35 | } 36 | } 37 | break; 38 | 39 | case NEW_CALENDAR: 40 | if (doc["summary"].as().equals(keyword)) 41 | { 42 | result = doc["id"].as(); 43 | } 44 | break; 45 | 46 | 47 | case EVENTS: 48 | if (doc["items"]) 49 | { 50 | JsonArray array = doc["items"].as(); 51 | for (JsonVariant event : array) 52 | { 53 | const char* id = event["id"]; 54 | const char* summary = event["summary"]; 55 | const char* start_str = event["start"]["dateTime"]; 56 | const char* end_str = event["end"]["dateTime"]; 57 | time_t start; 58 | time_t end; 59 | 60 | struct tm ts; 61 | strptime(start_str, "%FT%T%z", &ts); 62 | start = mktime(&ts); 63 | 64 | strptime(end_str, "%FT%T%z", &ts); 65 | end = mktime(&ts); 66 | m_eventList.addEvent(id, summary, start, end); 67 | } 68 | } 69 | result = m_eventList.size(); 70 | break; 71 | 72 | case NEW_EVENT: 73 | result = doc["id"].as(); 74 | break; 75 | 76 | case DELETE_EVENT: 77 | result = doc["noContent"].as(); 78 | break; 79 | } 80 | return result; 81 | } 82 | 83 | String GoogleCalendarAPI::readCalendarClient(const int filter, const char *keyword) 84 | { 85 | String payload; 86 | m_auth.readggClient(payload, true, false); 87 | return parsePayload(payload, filter, keyword); 88 | } 89 | 90 | const char *GoogleCalendarAPI::checkCalendar(const char *calendarSummary, bool create, const char* timeZone) 91 | { 92 | m_calendarId = ""; 93 | m_auth.sendCommand("GET ", CALENDAR_HOST, "/calendar/v3/users/me/calendarList", "", true); 94 | m_calendarId = readCalendarClient(CALENDARS, calendarSummary); 95 | /* calendar not present, create a new one */ 96 | if (!m_calendarId.length() && create) 97 | { 98 | String body = "{\"summary\": \""; 99 | body += calendarSummary; 100 | if (timeZone != nullptr) { 101 | body += "\", \"timeZone\":\""; 102 | body += timeZone; 103 | m_calendarTimeZone = timeZone; 104 | } 105 | body += "\"}"; 106 | m_auth.sendCommand("POST ", CALENDAR_HOST, "/calendar/v3/calendars", body.c_str(), true); 107 | m_calendarId = readCalendarClient(NEW_CALENDAR, calendarSummary); 108 | } 109 | return m_calendarId.c_str(); 110 | } 111 | 112 | int GoogleCalendarAPI::getEventList(const char *calendarId, const char *timeMin, const char *timeMax) 113 | { 114 | m_eventList.clear(); 115 | 116 | String request = "/calendar/v3/calendars/"; 117 | request += m_auth.urlencode(calendarId); 118 | request += "/events"; 119 | if (timeMin != nullptr&& strlen(timeMin)) 120 | { 121 | request += "?timeMin="; 122 | request += m_auth.urlencode(timeMin); 123 | if (timeMax != nullptr && strlen(timeMax)) 124 | { 125 | request += "&timeMax="; 126 | request += m_auth.urlencode(timeMax); 127 | } 128 | } 129 | m_auth.sendCommand("GET ", CALENDAR_HOST, request.c_str(), "", true); 130 | String res = readCalendarClient(EVENTS, calendarId); 131 | return res.toInt(); 132 | } 133 | 134 | int GoogleCalendarAPI::getEventList(const char *calendarId, time_t timeMin, time_t timeMax) 135 | { 136 | char min[25 + 1]; // RFC3339 timestamp 137 | char max[25 + 1]; // RFC3339 timestamp 138 | struct tm ts; 139 | 140 | memset(min, '\0', sizeof(min)); 141 | memset(max, '\0', sizeof(max)); 142 | 143 | 144 | if (timeMin != 0) 145 | { 146 | localtime_r(&timeMin, &ts); 147 | strftime(min, sizeof(min), "%FT%T%z", &ts); 148 | if (timeMax != 0) 149 | { 150 | localtime_r(&timeMax, &ts); 151 | strftime(max, sizeof(max), "%FT%T%z", &ts); 152 | } 153 | } 154 | else { 155 | time(&timeMin); 156 | localtime_r(&timeMin, &ts); 157 | strftime(min, sizeof(min), "%FT%T%z", &ts); 158 | } 159 | return getEventList(calendarId, min, max); 160 | } 161 | 162 | 163 | String GoogleCalendarAPI::createRRule(int recurType, int count) 164 | { 165 | String rule = "RRULE:FREQ="; 166 | rule += Freq[recurType]; 167 | rule += ";COUNT="; 168 | rule += count; 169 | return rule; 170 | } 171 | 172 | 173 | 174 | const char* GoogleCalendarAPI::addEvent(const char* calendarId, const char* summary, time_t start, time_t end, const char* recurrency) 175 | { 176 | char startStr[25+1]; 177 | char endStr[25+1]; 178 | 179 | struct tm ts; 180 | localtime_r(&start, &ts); 181 | strftime(startStr, sizeof(startStr), "%FT%T%z", &ts); 182 | localtime_r(&end, &ts); 183 | strftime(endStr, sizeof(endStr), "%FT%T%z", &ts); 184 | 185 | m_calendarId = ""; 186 | String request = "/calendar/v3/calendars/"; 187 | request += m_auth.urlencode(calendarId); 188 | request += "/events"; 189 | 190 | String body = "{\"summary\": \""; 191 | body += summary; 192 | body += "\",\"start\":{\"dateTime\":\""; 193 | body += startStr; 194 | body += "\", \"timeZone\":\""; 195 | body += m_calendarTimeZone; 196 | body += "\"},\"end\":{\"dateTime\":\""; 197 | body += endStr; 198 | body += "\", \"timeZone\":\""; 199 | body += m_calendarTimeZone; 200 | if (recurrency) { 201 | body += "\"},\"recurrence\":[\""; 202 | body += recurrency; 203 | body += "\"]}"; 204 | } 205 | else { 206 | body += "\"}}"; 207 | } 208 | m_auth.sendCommand("POST ", CALENDAR_HOST, request.c_str(), body.c_str(), true); 209 | m_calendarId = readCalendarClient(NEW_EVENT); 210 | 211 | return m_calendarId.c_str(); 212 | } 213 | 214 | const char* GoogleCalendarAPI::addEvent(const char* calendarId, const char* summary, time_t start, time_t end, int recurrency, int count) 215 | { 216 | String rule = createRRule(recurrency, count); 217 | return addEvent(calendarId, summary, start, end, rule.c_str()); 218 | } 219 | 220 | 221 | const char* GoogleCalendarAPI::quickAddEvent(const char* calendarId, const char* sentence) 222 | { 223 | m_calendarId = ""; 224 | String request = "/calendar/v3/calendars/"; 225 | request += m_auth.urlencode(calendarId); 226 | request += "/events/quickAdd?text="; 227 | request += m_auth.urlencode(sentence); 228 | 229 | m_auth.sendCommand("POST ", CALENDAR_HOST, request.c_str(), "{}", true); 230 | m_calendarId = readCalendarClient(NEW_EVENT); 231 | 232 | return m_calendarId.c_str(); 233 | } 234 | 235 | bool GoogleCalendarAPI::deleteEvent(const char* calendarId, const char* eventId) 236 | { 237 | // DELETE https://www.googleapis.com/calendar/v3/calendars/calendarId/events/eventId 238 | m_calendarId = ""; 239 | String request = "/calendar/v3/calendars/"; 240 | request += m_auth.urlencode(calendarId); 241 | request += "/events/"; 242 | request += eventId; 243 | 244 | m_auth.sendCommand("DELETE ", CALENDAR_HOST, request.c_str(), "", true); 245 | m_calendarId = readCalendarClient(DELETE_EVENT); 246 | return m_calendarId.equals("true");; 247 | } -------------------------------------------------------------------------------- /src/GoogleCalendar.h: -------------------------------------------------------------------------------- 1 | #ifndef GOOGLE_CALENDAR_API 2 | #define GOOGLE_CALENDAR_API 3 | 4 | #include "GoogleOAuth2.h" 5 | 6 | #define CALENDAR_HOST "www.googleapis.com" 7 | 8 | class EventList 9 | { 10 | friend class GoogleCalendar; 11 | 12 | public: 13 | struct EventItem 14 | { 15 | String id; 16 | String summary; 17 | time_t start; 18 | time_t stop; 19 | EventItem *nextItem = nullptr; 20 | }; 21 | 22 | ~EventList() 23 | { 24 | EventItem *p_item = m_firstItem; 25 | while (p_item != nullptr) 26 | { 27 | /* Get the next file pointer before destroying the obj */ 28 | EventItem *p_next_item = p_item->nextItem; 29 | 30 | /* Delete the obj */ 31 | delete p_item; 32 | 33 | /* Move to next obj */ 34 | p_item = p_next_item; 35 | } 36 | }; 37 | 38 | void clear() 39 | { 40 | m_firstItem = nullptr; 41 | m_lastItem = nullptr; 42 | } 43 | 44 | unsigned int size() const 45 | { 46 | return m_eventCount; 47 | } 48 | 49 | void addEvent(const char *id, const char *summary, time_t start, time_t stop) 50 | { 51 | for (EventItem *item = m_firstItem; item != nullptr; item = item->nextItem) 52 | { 53 | if (item->id.equals(id)) 54 | return; // id already present in list 55 | } 56 | EventItem *thisItem = new EventItem(); 57 | if (m_firstItem != nullptr) 58 | m_lastItem->nextItem = thisItem; 59 | else 60 | m_firstItem = thisItem; 61 | m_lastItem = thisItem; 62 | m_eventCount++; 63 | thisItem->id = id; 64 | thisItem->summary = summary; 65 | thisItem->start = start; 66 | thisItem->stop = stop; 67 | } 68 | 69 | const char *getEventId(int index) const 70 | { 71 | int counter = 0; 72 | for (EventItem *item = m_firstItem; item != nullptr; item = item->nextItem) 73 | { 74 | if (counter == index) 75 | return item->id.c_str(); 76 | counter++; 77 | } 78 | return "not found"; 79 | } 80 | 81 | uint32_t getStartTime(const char *id) const 82 | { 83 | EventItem *item = getEvent(id); 84 | if (item != nullptr) 85 | return item->start; 86 | return 0; 87 | } 88 | 89 | uint32_t getStopTime(const char *id) const 90 | { 91 | EventItem *item = getEvent(id); 92 | if (item != nullptr) 93 | return item->stop; 94 | return 0; 95 | } 96 | 97 | const char *getSummary(const char *id) const 98 | { 99 | EventItem *item = getEvent(id); 100 | if (item != nullptr) 101 | return item->summary.c_str(); 102 | return "not found"; 103 | } 104 | 105 | void printList() const 106 | { 107 | for (EventItem *item = m_firstItem; item != nullptr; item = item->nextItem) 108 | { 109 | Serial.print("Event id: "); 110 | Serial.print(item->id); 111 | Serial.print("\tsummary: "); 112 | Serial.print(item->summary); 113 | Serial.print("\tstart: "); 114 | Serial.print(item->start); 115 | Serial.print("\tend: "); 116 | Serial.println(item->stop); 117 | } 118 | } 119 | 120 | EventItem *getEvent(const char *id) const 121 | { 122 | for (EventItem *item = m_firstItem; item != nullptr; item = item->nextItem) 123 | if (item->id.equals(id)) 124 | return item; 125 | return nullptr; 126 | } 127 | 128 | EventItem *getEvent(int index) const 129 | { 130 | int counter = 0; 131 | for (EventItem *item = m_firstItem; item != nullptr; item = item->nextItem) { 132 | if (index == counter++) 133 | return item; 134 | } 135 | return nullptr; 136 | } 137 | 138 | 139 | private: 140 | unsigned int m_eventCount; 141 | EventItem *m_firstItem = nullptr; 142 | EventItem *m_lastItem = nullptr; 143 | }; 144 | 145 | class GoogleCalendarAPI 146 | { 147 | public: 148 | enum 149 | { 150 | NONE, 151 | DAILY, 152 | WEEKLY, 153 | MONTHLY, 154 | YEARLY 155 | }; 156 | const char Freq[5][10] = {"", "DAILY", "WEEKLY", "MONTHLY", "YEARLY"}; 157 | 158 | /* Constructor that receive const reference to 'GoogleOAuth2' object and a reference to 'EventList'*/ 159 | GoogleCalendarAPI(GoogleOAuth2 &auth, EventList &list) : m_auth(auth), m_eventList(list) {} 160 | 161 | /* Destructor, does nothing */ 162 | ~GoogleCalendarAPI() {} 163 | 164 | /* Check for a specific calendar with proved summary, and optionally create */ 165 | const char *checkCalendar(const char *calendarSummary, bool create = true, const char *timeZone = nullptr); 166 | inline const char *checkCalendar(const String &calendarSummary, bool create, const char *timeZone) 167 | { 168 | return checkCalendar(calendarSummary.c_str(), create, timeZone); 169 | } 170 | 171 | /* Get the list of events in the specified time range (RFC3339 timestamp with mandatory time zone offset) */ 172 | int getEventList(const char *calendarId, const char *timeMin, const char *timeMax); 173 | inline int getEventList(const String &calendarId, const char *timeMin, const char *timeMax) 174 | { 175 | return getEventList(calendarId.c_str(), timeMin, timeMax); 176 | } 177 | 178 | /* Get the list of events in the specified time range (EPOCH timestamp) */ 179 | int getEventList(const char *calendarId, time_t timeMin = 0, time_t timeMax = 0); 180 | inline int getEventList(const String &calendarId, time_t timeMin = 0, time_t timeMax = 0) 181 | { 182 | return getEventList(calendarId.c_str(), timeMin, timeMax); 183 | } 184 | 185 | inline void prinEventList() 186 | { 187 | m_eventList.printList(); 188 | } 189 | 190 | /* Add a new event to specified calendar, return the id of new event 191 | optional recurrency rules can be passed as array of string eg: "RRULE:FREQ=DAILY;COUNT=2" 192 | */ 193 | const char *addEvent(const char *calendarId, const char *summary, time_t start, time_t end, const char *recurrency = nullptr); 194 | 195 | /* Add a new event to specified calendar, return the id of new event 196 | optional recurrency rules can be passed as parameter eg: DAILY, 2 times 197 | */ 198 | const char *addEvent(const char *calendarId, const char *summary, time_t start, time_t end, int recurrency = 0, int count = 0); 199 | 200 | /* Creates an event based on a simple text string, return the id of new event 201 | example sentence: "Do somenthing at Somewhere on June 3rd 10am-10:25am" 202 | */ 203 | const char *quickAddEvent(const char *calendarId, const char *sentence); 204 | inline const char *quickAddEvent(const String& calendarId, const String& sentence) 205 | { 206 | return quickAddEvent(calendarId.c_str(), sentence.c_str()); 207 | } 208 | 209 | /* Deletes an event of a specific calendar */ 210 | bool deleteEvent(const char *calendarId, const char* eventId); 211 | inline bool deleteEvent(const String& calendarId, const String& eventId) 212 | { 213 | return deleteEvent(calendarId.c_str(), eventId.c_str()); 214 | } 215 | 216 | /* Utility method for getting a time_t variable from specific datetime */ 217 | inline time_t getEpochTime(int year, int month, int day, int hours, int minutes, int seconds = 0) { 218 | struct tm ts; 219 | getLocalTime(&ts); 220 | //ts.tm_isdst = 1; 221 | ts.tm_sec = seconds; 222 | ts.tm_min = minutes; 223 | ts.tm_hour = hours; 224 | ts.tm_mday = day; 225 | ts.tm_mon = month - 1; 226 | ts.tm_year = year - 1900; 227 | return mktime(&ts); 228 | } 229 | 230 | inline EventList::EventItem* getEvent(int index) { 231 | return m_eventList.getEvent(index); 232 | } 233 | 234 | inline bool eventInProgress(int index) { 235 | EventList::EventItem* event = getEvent(index); 236 | time_t now = time(nullptr); 237 | bool res = false; 238 | if (event != nullptr) 239 | res = now >= event->start && now <= event->stop; 240 | return res; 241 | } 242 | 243 | private: 244 | enum 245 | { 246 | CALENDARS, 247 | EVENTS, 248 | NEW_CALENDAR, 249 | NEW_EVENT, 250 | DELETE_EVENT 251 | }; 252 | 253 | /* Default constructor is declared but NOT implemented */ 254 | GoogleCalendarAPI(); 255 | 256 | GoogleOAuth2 & m_auth; 257 | EventList & m_eventList; 258 | 259 | String m_calendarId = ""; 260 | String m_calendarTimeZone = ""; 261 | 262 | // Class specialized parser 263 | String readCalendarClient(const int filter, const char *keyword = nullptr); 264 | String parsePayload(const String &payload, const int filter, const char *gFile); 265 | 266 | String createRRule(int recurType, int count); 267 | }; 268 | 269 | #endif 270 | -------------------------------------------------------------------------------- /src/GoogleDrive.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GOOGLEO_DRIVE_API 3 | #define GOOGLEO_DRIVE_API 4 | 5 | #include "GoogleFilelist.h" 6 | #include "GoogleOAuth2.h" 7 | 8 | #define API_HOST "www.googleapis.com" 9 | 10 | class GoogleDriveAPI 11 | { 12 | friend class GoogleSheetAPI; 13 | 14 | public: 15 | //GoogleDriveAPI(fs::FS &fs, Client &client, GoogleFilelist *list = nullptr); 16 | GoogleDriveAPI(GoogleOAuth2 *auth, GoogleFilelist *list = nullptr); 17 | ~GoogleDriveAPI(){ delete m_auth;}; 18 | 19 | unsigned int getNumFiles() const; 20 | const char *getFileName(int index) const; 21 | const char *getFileId(int index) const; 22 | const char *getFileId(const char *name) const; 23 | 24 | // Methods to store and retrieve app filder id (if files are organized by folder) 25 | inline void setAppFolderId(const char *folderId) 26 | { 27 | m_driveParentId = String(folderId); 28 | } 29 | inline void setAppFolderId(const String& folderId) 30 | { 31 | m_driveParentId = folderId; 32 | } 33 | inline const char *getAppFolderId() 34 | { 35 | return m_driveParentId.c_str(); 36 | } 37 | 38 | // return the google ID for files or folder 39 | const char *createFolder(const char *folderName, const char *parent, bool isName = false); 40 | inline const char *createFolder(const String &folderName, const char *parent, bool isName = false) 41 | { 42 | return createFolder(folderName.c_str(), parent, isName); 43 | } 44 | inline const char *createFolder(const String &folderName, const String &parent, bool isName = false) 45 | { 46 | return createFolder(folderName.c_str(), parent.c_str(), isName); 47 | } 48 | 49 | bool setParentFolderId(const char *fileId, const char *parentId); 50 | 51 | const char *searchFile(const char *fileName, const char *parentId = nullptr); 52 | inline const char *searchFile(const String &fileName, const String &parentId) 53 | { 54 | return searchFile(fileName.c_str(), parentId.c_str()); 55 | } 56 | inline const char *searchFile(const String &fileName) 57 | { 58 | return searchFile(fileName.c_str(), nullptr); 59 | } 60 | 61 | bool updateFileList(); 62 | void printFileList() const; 63 | 64 | // Upload or update file 65 | const char *uploadFile(const char *path, const char *id, bool isUpdate = true); 66 | const char *uploadFile(const String &path, const String &id, bool isUpdate = true); 67 | 68 | protected: 69 | enum 70 | { 71 | WAIT_FILE, 72 | SAVE_ID, 73 | SAVE_NAME, 74 | SAVE_TYPE, 75 | SEARCH_ID, 76 | UPLOAD_ID, 77 | NEW_FILE, 78 | UPDATE_LIST 79 | }; 80 | GoogleOAuth2 *m_auth = nullptr; 81 | GoogleFilelist *m_filelist = nullptr; 82 | String m_driveParentId; 83 | String m_driveFileId; 84 | bool sendMultipartFormData(const char *path, const char *filename, const char *id, bool update = false); 85 | 86 | String parseLine(const String &line, const int filter, GoogleFile_t *gFile); 87 | String uploadFileName; 88 | 89 | // Class specialized parser 90 | bool readDriveClient(const int filter, const char *keyword = nullptr, bool payload_gzip = true); 91 | bool parsePayload(const String &payload, const int filter, const char *gFile); 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /src/GoogleFilelist.cpp: -------------------------------------------------------------------------------- 1 | #include "GoogleFilelist.h" 2 | 3 | GoogleFilelist::~GoogleFilelist() 4 | { 5 | GoogleFile_t * p_file = m_firstFile; 6 | 7 | while( p_file != nullptr ) 8 | { 9 | /* Get the next file pointer before destroying the obj */ 10 | GoogleFile_t * p_next_file = p_file->nextFile; 11 | 12 | /* Delete the obj */ 13 | delete p_file; 14 | 15 | /* Move to next obj */ 16 | p_file = p_next_file; 17 | } 18 | } 19 | 20 | unsigned int GoogleFilelist::size() const 21 | { 22 | return m_filesCount; 23 | } 24 | 25 | void GoogleFilelist::clearList() 26 | { 27 | m_firstFile = nullptr; 28 | m_lastFile = nullptr; 29 | } 30 | 31 | void GoogleFilelist::addFile(const char *name, const char *id, bool isFolder) 32 | { 33 | 34 | for (GoogleFile_t *file = m_firstFile; file != nullptr; file = file->nextFile) 35 | { 36 | if (file->id.equals(id)) 37 | { 38 | log_error("ID %s already present in list\n", id); 39 | return; // File with provided id already present in list 40 | } 41 | } 42 | 43 | GoogleFile_t *thisFile = new GoogleFile_t(); 44 | if (m_firstFile != nullptr) 45 | m_lastFile->nextFile = thisFile; 46 | else 47 | m_firstFile = thisFile; 48 | 49 | m_lastFile = thisFile; 50 | m_filesCount++; 51 | thisFile->name = name; 52 | thisFile->id = id; 53 | thisFile->isFolder = isFolder; 54 | } 55 | 56 | void GoogleFilelist::addFile(const GoogleFile_t &gFile) 57 | { 58 | addFile(gFile.name.c_str(), gFile.id.c_str(), gFile.isFolder); 59 | } 60 | 61 | void GoogleFilelist::addFile(const String &name, const String &id, bool isFolder) 62 | { 63 | addFile(name.c_str(), id.c_str(), isFolder); 64 | } 65 | 66 | const char *GoogleFilelist::getFileName(int index) const 67 | { 68 | int counter = 0; 69 | for (GoogleFile_t *file = m_firstFile; file != nullptr; file = file->nextFile) 70 | { 71 | if (counter == index) 72 | return file->name.c_str(); 73 | counter++; 74 | } 75 | return nullptr; 76 | } 77 | 78 | const char *GoogleFilelist::getFileId(int index) const 79 | { 80 | int counter = 0; 81 | for (GoogleFile_t *file = m_firstFile; file != nullptr; file = file->nextFile) 82 | { 83 | if (counter == index) 84 | return file->id.c_str(); 85 | counter++; 86 | } 87 | return nullptr; 88 | } 89 | 90 | const char *GoogleFilelist::getFileId(const char *name) const 91 | { 92 | for (GoogleFile_t *file = m_firstFile; file != nullptr; file = file->nextFile) 93 | { 94 | if (file->name.equals(name)) 95 | return file->id.c_str(); 96 | } 97 | return nullptr; 98 | } 99 | 100 | const char *GoogleFilelist::getFileId(const String &name) const 101 | { 102 | return getFileId(name.c_str()); 103 | } 104 | 105 | bool GoogleFilelist::isInList(const char *id) const 106 | { 107 | for (GoogleFile_t *file = m_firstFile; file != nullptr; file = file->nextFile) 108 | { 109 | if (file->id.equals(id)) 110 | return true; 111 | } 112 | return false; 113 | } 114 | 115 | bool GoogleFilelist::isFolder(int index) const 116 | { 117 | int counter = 0; 118 | for (GoogleFile_t *file = m_firstFile; file != nullptr; file = file->nextFile) 119 | { 120 | if (file->isFolder && counter == index) 121 | return true; 122 | counter++; 123 | } 124 | return false; 125 | } 126 | 127 | bool GoogleFilelist::isFolder(const char *name) const 128 | { 129 | for (GoogleFile_t *file = m_firstFile; file != nullptr; file = file->nextFile) 130 | { 131 | if (file->isFolder && file->name.equals(name)) 132 | return true; 133 | } 134 | return false; 135 | } 136 | 137 | bool GoogleFilelist::isFolder(String &name) const 138 | { 139 | return isFolder(name.c_str()); 140 | } 141 | 142 | 143 | void GoogleFilelist::printList() const 144 | { 145 | for (GoogleFile_t *file = m_firstFile; file != nullptr; file = file->nextFile) 146 | { 147 | if (file->isFolder) 148 | Serial.print("folder:\t"); 149 | else 150 | Serial.print("file:\t"); 151 | Serial.print(file->name); 152 | Serial.print("\t "); 153 | Serial.println(file->id); 154 | } 155 | } -------------------------------------------------------------------------------- /src/GoogleFilelist.h: -------------------------------------------------------------------------------- 1 | #include "GoogleOAuth2.h" 2 | 3 | #ifndef GOOGLE_FILE_LIST 4 | #define GOOGLE_FILE_LIST 5 | 6 | struct GoogleFile_t{ 7 | String name; 8 | String id; 9 | bool isFolder; 10 | GoogleFile_t *nextFile = nullptr; 11 | }; 12 | 13 | class GoogleFilelist { 14 | 15 | public: 16 | ~GoogleFilelist(); 17 | 18 | void clearList(); 19 | unsigned int size() const; 20 | 21 | void addFile(const char* name, const char* id, bool isFolder); 22 | void addFile(const String& name, const String& id_t, bool isFolder); 23 | void addFile(const GoogleFile_t& gFile); 24 | 25 | const char* getFileName(int index) const; 26 | const char* getFileId(int index) const; 27 | const char* getFileId(const char* name) const; 28 | const char* getFileId(const String& name) const; 29 | 30 | bool isFolder(int index) const; 31 | bool isFolder(const char* name) const; 32 | bool isFolder(String& name) const; 33 | bool isInList(const char* id) const; 34 | 35 | void printList() const; 36 | 37 | private: 38 | 39 | unsigned int m_filesCount = 0; 40 | GoogleFile_t *m_firstFile = nullptr; 41 | GoogleFile_t *m_lastFile = nullptr; 42 | }; 43 | 44 | #endif -------------------------------------------------------------------------------- /src/GoogleGmail.cpp: -------------------------------------------------------------------------------- 1 | #include "GoogleGmail.h" 2 | #include "Base64.h" 3 | 4 | 5 | 6 | 7 | GoogleGmailAPI::GoogleGmailAPI(GoogleOAuth2 *auth, GmailList *list) : m_auth(auth) 8 | { 9 | if (list != nullptr) 10 | m_mailList = list; 11 | } 12 | 13 | 14 | String GoogleGmailAPI::parsePayload(const String& payload, const int filter, const char* keyword) 15 | { 16 | #if defined(ESP8266) 17 | DynamicJsonDocument doc(ESP.getMaxFreeBlockSize() - 512); 18 | #elif defined(ESP32) 19 | DynamicJsonDocument doc(ESP.getMaxAllocHeap() - 512); 20 | #else 21 | DynamicJsonDocument doc(payload.length() + 256); 22 | #endif 23 | DeserializationError err = deserializeJson(doc, payload); 24 | if (err) { 25 | log_error("deserializeJson() failed\n"); 26 | log_error("%s\n", err.c_str()); 27 | return ""; 28 | } 29 | 30 | String result = ""; 31 | switch (filter) { 32 | case MAIL_ID: 33 | if (doc["id"]) 34 | result = doc["id"].as(); 35 | break; 36 | 37 | case MAIL_LIST: 38 | if (doc["messages"]) { 39 | result = doc["resultSizeEstimate"].as(); 40 | JsonArray array = doc["messages"].as(); 41 | for(JsonVariant message : array) { 42 | m_mailList->addMailId(message["id"].as().c_str(), false); 43 | } 44 | } 45 | break; 46 | 47 | case READ_SNIPPET: 48 | if (doc["snippet"]) { 49 | result = doc["snippet"].as(); 50 | GmailList::mailItem* mail = m_mailList->getItem(keyword); 51 | JsonArray array = doc["payload"]["headers"].as(); 52 | for(JsonVariant header : array) { 53 | if (header["name"].as().equals("Date")) 54 | mail->date = header["value"].as(); 55 | if (header["name"].as().equals("Subject")) 56 | mail->subject = header["value"].as(); 57 | if (header["name"].as().equals("From")) 58 | mail->from = header["value"].as(); 59 | } 60 | } 61 | break; 62 | 63 | case READ_EMAIL: 64 | if (doc["payload"]) { 65 | GmailList::mailItem* mail = m_mailList->getItem(keyword); 66 | JsonArray array = doc["payload"]["headers"].as(); 67 | for(JsonVariant header : array) { 68 | if (header["name"].as().equals("Date")) 69 | mail->date = header["value"].as(); 70 | if (header["name"].as().equals("Subject")) 71 | mail->subject = header["value"].as(); 72 | if (header["name"].as().equals("From")) 73 | mail->from = header["value"].as(); 74 | } 75 | result = Base64::decode(doc["payload"]["parts"][0]["body"]["data"].as()); 76 | } 77 | break; 78 | } 79 | return result; 80 | } 81 | 82 | 83 | String GoogleGmailAPI::readGMailClient(const int filter, const char* keyword) 84 | { 85 | String payload; 86 | m_auth->readggClient(payload); 87 | return parsePayload(payload, filter, keyword); 88 | } 89 | 90 | 91 | bool GoogleGmailAPI::setMessageRead(const char* idEmail){ 92 | size_t len = strlen_P(PSTR("/gmail/v1/users/me/messages//modify")) + strlen(idEmail) + 1; 93 | char* cmd = new char[len]; 94 | snprintf_P(cmd, len, PSTR("/gmail/v1/users/me/messages/%s/modify"), idEmail); 95 | 96 | m_auth->sendCommand("POST ", GMAIL_HOST, cmd, "{\"removeLabelIds\": [\"UNREAD\"]}", true); 97 | return (readGMailClient(MAIL_ID, idEmail) != ""); 98 | } 99 | 100 | 101 | int GoogleGmailAPI::getMailData(const char* idEmail){ 102 | String cmd = PSTR("/gmail/v1/users/me/messages/%s?format=metadata"); 103 | cmd += idEmail; 104 | 105 | m_auth->sendCommand("GET ", GMAIL_HOST, cmd.c_str(), "", true); 106 | return readGMailClient(READ_SNIPPET, idEmail ).length(); 107 | } 108 | 109 | int GoogleGmailAPI::getMailList(const char* from, bool unread, uint32_t maxResults){ 110 | String uri = F("/gmail/v1/users/me/messages?maxResults="); 111 | uri += maxResults; 112 | 113 | if(from != nullptr || unread){ 114 | uri += F("&q="); 115 | if(from != nullptr && unread){ 116 | uri += F("from:"); 117 | uri += from; 118 | uri += F("%20is:unread"); 119 | } 120 | else if(from != nullptr){ 121 | uri += F("from:"); 122 | uri += from; 123 | } 124 | else if (unread) 125 | uri += F("is:unread"); 126 | } 127 | 128 | m_auth->sendCommand("GET ", GMAIL_HOST, uri.c_str(), "", true); 129 | return readGMailClient(MAIL_LIST).toInt(); 130 | } 131 | 132 | 133 | String GoogleGmailAPI::sendEmail(const char* to, const char* subject, const char* message){ 134 | 135 | String tempsStr = F("To: "); 136 | tempsStr += to; 137 | tempsStr += F("\r\nSubject: "); 138 | tempsStr += subject; 139 | tempsStr += F("\r\n\r\n"); 140 | tempsStr += message; 141 | 142 | String payload = F("{\"raw\": \""); 143 | payload += base64::encode(tempsStr); 144 | payload += F("\"}"); 145 | 146 | m_auth->sendCommand("POST ", GMAIL_HOST, "/gmail/v1/users/me/messages/send", payload.c_str(), true); 147 | return readGMailClient(SEND_EMAIL); 148 | } 149 | 150 | 151 | String GoogleGmailAPI::readSnippet(const char* idEmail){ 152 | return readMail( idEmail, true); 153 | } 154 | 155 | 156 | String GoogleGmailAPI::readMail(const char* idEmail, bool snippet){ 157 | String cmd = F("/gmail/v1/users/me/messages/"); 158 | cmd += idEmail; 159 | m_auth->sendCommand("GET ", GMAIL_HOST, cmd.c_str(), "", true); 160 | if (snippet) 161 | return readGMailClient(READ_SNIPPET, idEmail); 162 | else 163 | return readGMailClient(READ_EMAIL, idEmail); 164 | } 165 | 166 | -------------------------------------------------------------------------------- /src/GoogleGmail.h: -------------------------------------------------------------------------------- 1 | #ifndef GOOGLEO_GMAIL_API 2 | #define GOOGLEO_GMAIL_API 3 | 4 | #include "GoogleOAuth2.h" 5 | 6 | #define GMAIL_HOST "gmail.googleapis.com" 7 | 8 | class GmailList 9 | { 10 | struct mailItem 11 | { 12 | String id; 13 | String from; 14 | String subject; 15 | String date; 16 | bool read = false; 17 | mailItem *nextItem = nullptr; 18 | }; 19 | 20 | friend class GoogleGmailAPI; 21 | 22 | public: 23 | ~GmailList() 24 | { 25 | mailItem *p_item = m_firstItem; 26 | while (p_item != nullptr) 27 | { 28 | /* Get the next file pointer before destroying the obj */ 29 | mailItem *p_next_item = p_item->nextItem; 30 | 31 | /* Delete the obj */ 32 | delete p_item; 33 | 34 | /* Move to next obj */ 35 | p_item = p_next_item; 36 | } 37 | }; 38 | 39 | void clear() 40 | { 41 | m_firstItem = nullptr; 42 | m_lastItem = nullptr; 43 | } 44 | 45 | unsigned int size() const 46 | { 47 | return m_mailCount; 48 | } 49 | 50 | void addMailId(const char *id, bool read) 51 | { 52 | for (mailItem *item = m_firstItem; item != nullptr; item = item->nextItem) 53 | { 54 | if (item->id.equals(id)) 55 | return; // id already present in list 56 | } 57 | mailItem *thisItem = new mailItem(); 58 | if (m_firstItem != nullptr) 59 | m_lastItem->nextItem = thisItem; 60 | else 61 | m_firstItem = thisItem; 62 | m_lastItem = thisItem; 63 | m_mailCount++; 64 | thisItem->read = read; 65 | thisItem->id = id; 66 | } 67 | 68 | const char *getMailId(int index) const 69 | { 70 | int counter = 0; 71 | for (mailItem *item = m_firstItem; item != nullptr; item = item->nextItem) 72 | { 73 | if (counter == index) 74 | return item->id.c_str(); 75 | counter++; 76 | } 77 | return "not found"; 78 | } 79 | 80 | const char *getFrom(const char *id) const 81 | { 82 | mailItem *item = getItem(id); 83 | if (item != nullptr) 84 | { 85 | return item->from.c_str(); 86 | } 87 | return "not found"; 88 | } 89 | 90 | const char *getDate(const char *id) const 91 | { 92 | mailItem *item = getItem(id); 93 | if (item != nullptr) 94 | return item->date.c_str(); 95 | return 0; 96 | } 97 | 98 | const char *getSubject(const char *id) const 99 | { 100 | mailItem *item = getItem(id); 101 | if (item != nullptr) 102 | return item->subject.c_str(); 103 | return "not found"; 104 | } 105 | 106 | void printList() const 107 | { 108 | for (mailItem *item = m_firstItem; item != nullptr; item = item->nextItem) 109 | { 110 | Serial.print("\tid: "); 111 | Serial.println(item->id); 112 | } 113 | } 114 | 115 | mailItem *getItem(const char *id) const 116 | { 117 | for (mailItem *item = m_firstItem; item != nullptr; item = item->nextItem) 118 | if (item->id.equals(id)) 119 | return item; 120 | return nullptr; 121 | } 122 | 123 | private: 124 | unsigned int m_mailCount; 125 | mailItem *m_firstItem = nullptr; 126 | mailItem *m_lastItem = nullptr; 127 | }; 128 | 129 | class GoogleGmailAPI 130 | { 131 | public: 132 | GoogleGmailAPI(GoogleOAuth2 *auth, GmailList *list = nullptr); 133 | ~GoogleGmailAPI() { delete m_auth; }; 134 | 135 | // Send a new email from ESP 136 | String sendEmail(const char *to, const char *subject, const char *message); 137 | String sendEmail(const String &to, const String &subject, const String &message) 138 | { 139 | return sendEmail(to.c_str(), subject.c_str(), message.c_str()); 140 | } 141 | 142 | // Return the number of unreaded messages in list 143 | int getMailList(const char *from = nullptr, bool unread = true, uint32_t maxResults = 100); 144 | 145 | // Return the body of message as snippet or as complete message plain text 146 | String readMail(const char *idEmail, bool snippet = false); 147 | String readSnippet(const char *idEmail); 148 | 149 | // Get the metadata for message id 150 | int getMailData(const char *idEmail); 151 | 152 | // Set a specific message id as read 153 | bool setMessageRead(const char *idEmail); 154 | 155 | private: 156 | enum 157 | { 158 | MAIL_ID, 159 | MAIL_LIST, 160 | READ_SNIPPET, 161 | READ_EMAIL, 162 | SEND_EMAIL 163 | }; 164 | 165 | GoogleOAuth2 *m_auth = nullptr; 166 | GmailList *m_mailList = nullptr; 167 | 168 | // Class specialized parser 169 | String readGMailClient(const int filter, const char *keyword = nullptr); 170 | String parsePayload(const String &payload, const int filter, const char *gFile); 171 | }; 172 | 173 | #endif 174 | -------------------------------------------------------------------------------- /src/GoogleOAuth2.h: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include 3 | #include // https://github.com/cotestatnt/esp-fs-webserver 4 | 5 | #if defined(ESP8266) 6 | #include 7 | #elif defined(ESP32) 8 | #include 9 | #endif 10 | #include 11 | #include 12 | 13 | #ifndef GOOGLE_OAUTH2 14 | #define GOOGLE_OAUTH2 15 | 16 | #ifndef DEBUG_ENABLE 17 | #define DEBUG_ENABLE 0 18 | #endif 19 | 20 | #ifndef DEBUG_FUNCTION_CALL 21 | #define DEBUG_FUNCTION_CALL 0 22 | #endif 23 | 24 | #include "SerialLog.h" 25 | #include "Const.h" 26 | 27 | class GoogleOAuth2 28 | { 29 | 30 | public: 31 | 32 | enum 33 | { 34 | INIT, 35 | REQUEST_AUTH, 36 | GOT_TOKEN, 37 | REFRESH_TOKEN, 38 | INVALID 39 | }; 40 | 41 | GoogleOAuth2(fs::FS &fs, Client &client); 42 | ~GoogleOAuth2(){}; 43 | 44 | bool begin(const char *id, const char *secret, const char *_scope, const char *api_key, const char *redirect_uri); 45 | bool begin(); 46 | unsigned int getState(); 47 | void printConfig() const; 48 | void clearConfig() const; 49 | const char *getUserCode() const; 50 | 51 | inline bool isAuthorized() 52 | { 53 | return (getState() == GOT_TOKEN); 54 | } 55 | 56 | /* send an HTTP command to Google server */ 57 | void sendCommand(const char *const &rest, const char *const &host, 58 | const char *const &command, const char *const &body, bool bearer); 59 | 60 | /* Return true if data succesfull parsed */ 61 | bool readggClient(String &payload, bool keep_connection = false, bool payload_gzip = true); 62 | 63 | /* read a single parameter from gapi_config-json file */ 64 | const String readParam(const char *keyword) const; 65 | 66 | /* connect to Google server */ 67 | bool doConnection(const char *host) const; 68 | 69 | /* Check if access token is still valid (local time) */ 70 | void checkRefreshTime(); 71 | 72 | /* Pointer to WiFi or Ethernet */ 73 | Client *m_ggclient; 74 | 75 | /* Pointer to filesystem (where configuration files are stored) */ 76 | fs::FS *m_filesystem; 77 | 78 | /* encode url string utility */ 79 | String urlencode(const char *str); 80 | 81 | private: 82 | const char *m_configFile = "/gapi_config.json"; 83 | uint32_t m_expires_at_ms = 0; 84 | unsigned int m_ggstate = INIT; 85 | 86 | String m_user_code = ""; 87 | String m_device_code = ""; 88 | String m_token_type = ""; 89 | 90 | /* Class specialized parser */ 91 | bool parsePayload(const String &payload); 92 | 93 | /* return true if access token is valid */ 94 | bool isAccessTokenValid(); 95 | 96 | /* return true if refresh access token succesfully */ 97 | bool refreshToken(bool stopClient = false); // return true on access token validù 98 | 99 | /* get from Google the device code */ 100 | bool requestDeviceCode(); 101 | 102 | /* wait for a reply from Google server during authorization worlkflow */ 103 | bool pollingAuthorize(); 104 | 105 | /* load app data configuration from filesystem (gapi_config.json") */ 106 | bool loadConfig(const char *id, const char *secret, const char *scope, const char *api_key, const char *redirect_uri) const; 107 | 108 | /* update a single parameter in gapi_config-json file */ 109 | bool writeParam(const char *keyword, const char *value) const; 110 | 111 | /* inflate gzipped payload received from Google server */ 112 | String gzipInflate(const String &compressedBytes) const; 113 | 114 | }; 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /src/GoogleSheet.cpp: -------------------------------------------------------------------------------- 1 | #include "GoogleSheet.h" 2 | 3 | enum 4 | { 5 | SPREADSHEET_ID, 6 | PARENT_ID, 7 | APPEND_ROW, 8 | SHEET_ID, 9 | ADD_SHEET_ID 10 | }; 11 | 12 | 13 | GoogleSheetAPI::GoogleSheetAPI(GoogleOAuth2 *auth, GoogleFilelist *list) : GoogleDriveAPI(auth, list) 14 | { 15 | m_spreadsheetId.reserve(MIN_ID_LEN + 11 + 1); 16 | } 17 | 18 | bool GoogleSheetAPI::parsePayload(const String &payload, const int filter, const char *keyword) 19 | { 20 | #if defined(ESP8266) 21 | DynamicJsonDocument doc(ESP.getMaxFreeBlockSize() - 512); 22 | #elif defined(ESP32) 23 | DynamicJsonDocument doc(ESP.getMaxAllocHeap() - 512); 24 | #else 25 | DynamicJsonDocument doc(payload.length() + 256); 26 | #endif 27 | DeserializationError err = deserializeJson(doc, payload); 28 | if (err) 29 | { 30 | log_error("deserializeJson() failed\n"); 31 | log_error("%s\n", err.c_str()); 32 | return false; 33 | } 34 | 35 | switch (filter) 36 | { 37 | case SPREADSHEET_ID: 38 | case APPEND_ROW: 39 | { 40 | if (doc["spreadsheetId"]) 41 | { 42 | m_spreadsheetId = doc["spreadsheetId"].as(); 43 | return true; 44 | } 45 | break; 46 | } 47 | 48 | case PARENT_ID: 49 | { 50 | if (doc["parents"][0]["id"].as().equals(keyword)) 51 | { 52 | m_spreadsheetId = doc["id"].as(); 53 | return true; 54 | } 55 | break; 56 | } 57 | 58 | case SHEET_ID: 59 | { 60 | if (doc["sheets"]) 61 | { 62 | JsonArray array = doc["sheets"].as(); 63 | for (JsonVariant sheet : array) 64 | { 65 | if (sheet["properties"]["title"].as().equals(keyword)) 66 | { 67 | m_spreadsheetId = sheet["properties"]["sheetId"].as(); 68 | return true; 69 | } 70 | } 71 | } 72 | break; 73 | } 74 | 75 | case ADD_SHEET_ID: 76 | { 77 | if (doc["replies"][0]["addSheet"]) 78 | { 79 | m_spreadsheetId = doc["replies"][0]["addSheet"]["properties"]["sheetId"].as(); 80 | return true; 81 | } 82 | break; 83 | } 84 | } 85 | return false; 86 | } 87 | 88 | bool GoogleSheetAPI::readSheetClient(const int filter, const char *keyword) 89 | { 90 | String payload; 91 | m_auth->readggClient(payload); 92 | return parsePayload(payload, filter, keyword); 93 | } 94 | 95 | bool GoogleSheetAPI::appendRowToSheet(const char *spreadsheetId, const char *range, const char *row) 96 | { 97 | String body = F("{\"values\": ["); 98 | body += row; 99 | body += F("]}\n"); 100 | 101 | String cmd = F("/v4/spreadsheets/"); 102 | cmd += spreadsheetId; 103 | cmd += F("/values/"); 104 | cmd += range; 105 | cmd += F(":append?insertDataOption=OVERWRITE&valueInputOption=USER_ENTERED"); 106 | 107 | m_auth->sendCommand("POST ", API_SHEET_HOST, cmd.c_str(), body.c_str(), true); 108 | m_spreadsheetId = ""; 109 | readSheetClient(SPREADSHEET_ID); 110 | return (m_spreadsheetId.length() > 0); 111 | } 112 | 113 | int32_t GoogleSheetAPI::newSheet(const char *sheetName, const char *spreadsheetId) 114 | { 115 | // https://sheets.googleapis.com/v4/spreadsheets/1w56hn_rRMYa13RV677wK0_X-YpusnEoLbEgd9dwTIyc:batchUpdate 116 | 117 | int32_t sheetId = -1; 118 | String body = F("{\"requests\":[{\"addSheet\":{\"properties\":{\"title\":\""); 119 | body += sheetName; 120 | body += F("\"}}}]}"); 121 | 122 | String cmd = F("/v4/spreadsheets/"); 123 | cmd += spreadsheetId; 124 | cmd += F(":batchUpdate"); 125 | 126 | m_auth->sendCommand("POST ", API_SHEET_HOST, cmd.c_str(), body.c_str(), true); 127 | m_spreadsheetId = ""; 128 | if (readSheetClient(ADD_SHEET_ID, sheetName)) 129 | { 130 | log_debug("New Sheet created, id: %ld\n", m_spreadsheetId.toInt()); 131 | sheetId = m_spreadsheetId.toInt(); 132 | } 133 | return sheetId; 134 | } 135 | 136 | int32_t GoogleSheetAPI::getSheetId(const char *sheetName, const char *spreadsheetId) 137 | { 138 | int32_t sheetId = -1; 139 | String cmd = F("/v4/spreadsheets/"); 140 | cmd += spreadsheetId; 141 | cmd += F("?&fields=sheets.properties"); 142 | m_auth->sendCommand("GET ", API_SHEET_HOST, cmd.c_str(), "", true); 143 | m_spreadsheetId = ""; 144 | 145 | if (readSheetClient(SHEET_ID, sheetName)) 146 | { 147 | log_debug("Sheet id: %ld\n", m_spreadsheetId.toInt()); 148 | sheetId = m_spreadsheetId.toInt(); 149 | } 150 | return sheetId; 151 | } 152 | 153 | bool GoogleSheetAPI::setSheetTitle(const char *sheetTitle, const char *spreadsheetId, int32_t sheetId) 154 | { 155 | String cmd = F("/v4/spreadsheets/"); 156 | cmd += spreadsheetId; 157 | cmd += F(":batchUpdate"); 158 | 159 | String body = F("{\"requests\": [{\"updateSheetProperties\": {\"properties\": {\"sheetId\": "); 160 | body += sheetId; 161 | body += F(",\"title\":\""); 162 | body += sheetTitle; 163 | body += F("\"},\"fields\": \"title\"}}]}"); 164 | 165 | m_auth->sendCommand("POST ", API_SHEET_HOST, cmd.c_str(), body.c_str(), true); 166 | m_spreadsheetId = ""; 167 | readSheetClient(SPREADSHEET_ID); 168 | return (m_spreadsheetId.length() > 0); 169 | } 170 | 171 | // Create spreadsheet (with Drive API) with a single sheet (default name) 172 | const char *GoogleSheetAPI::newSpreadsheet(const char *spreadsheetName, const char *parentId) 173 | { 174 | log_debug("Create new spreadsheet %s", spreadsheetName); 175 | m_auth->checkRefreshTime(); 176 | 177 | if (!m_auth->isAuthorized()) 178 | return nullptr; 179 | 180 | String body = F("{\"client_id\":\""); 181 | body += m_auth->readParam("client_id"); 182 | body += F("\",\"name\":\""); 183 | body += spreadsheetName; 184 | body += F("\",\"mimeType\":\"application/vnd.google-apps.spreadsheet\",\"parents\":[\""); 185 | body += parentId; 186 | body += F("\"]}"); 187 | 188 | m_auth->sendCommand("POST ", API_HOST, "/drive/v3/files", body.c_str(), true); 189 | m_driveFileId = ""; 190 | if (GoogleDriveAPI::readDriveClient(GoogleDriveAPI::UPLOAD_ID, spreadsheetName)) 191 | { 192 | log_debug("Spreadsheet id: %s\n", m_driveFileId.c_str()); 193 | } 194 | return m_driveFileId.c_str(); 195 | } 196 | 197 | bool GoogleSheetAPI::updateSheetList(String &query) 198 | { 199 | if (m_filelist == nullptr) 200 | { 201 | Serial.println(F("error: the class was initialized without GoogleFilelist object")); 202 | return false; 203 | } 204 | m_auth->checkRefreshTime(); 205 | 206 | String cmd = F("/drive/v3/files?q=mimeType='application/vnd.google-apps.spreadsheet'"); 207 | if (query.length()) 208 | { 209 | query.replace(" ", "%20"); 210 | cmd += query; 211 | } 212 | 213 | m_filelist->clearList(); 214 | m_auth->sendCommand("GET ", API_DRIVE_HOST, cmd.c_str(), "", true); 215 | return GoogleDriveAPI::readDriveClient(GoogleDriveAPI::UPDATE_LIST); 216 | } 217 | 218 | 219 | // Check if the spreadsheet exist in provided folder (with Drive API) 220 | const char* GoogleSheetAPI::isSpreadSheet(const char *spreadsheetName, const char *parentName, bool doCreateFolder) 221 | { 222 | m_parentId = searchFile(parentName); 223 | if(m_parentId.length() == 0 && doCreateFolder) { 224 | Serial.println("Parent not found"); 225 | m_parentId = createFolder(parentName, "root"); 226 | log_debug("App folder id: %s\n", m_parentId.c_str()); 227 | } 228 | 229 | m_driveFileId = searchFile(spreadsheetName, m_parentId.c_str()); 230 | return m_driveFileId.c_str(); 231 | } -------------------------------------------------------------------------------- /src/GoogleSheet.h: -------------------------------------------------------------------------------- 1 | #ifndef GOOGLE_SHEET_API 2 | #define GOOGLE_SHEET_API 3 | 4 | #include "GoogleDrive.h" 5 | 6 | #define API_DRIVE_HOST "www.googleapis.com" 7 | #define API_SHEET_HOST "sheets.googleapis.com" 8 | 9 | #define MAX_ROW_LEN 512 10 | 11 | class GoogleSheetAPI : public GoogleDriveAPI 12 | { 13 | 14 | public: 15 | //GoogleSheetAPI(fs::FS &fs, Client &client, GoogleFilelist *list = nullptr); 16 | GoogleSheetAPI(GoogleOAuth2 *auth, GoogleFilelist *list = nullptr); 17 | ~GoogleSheetAPI(){ delete m_auth;}; 18 | 19 | // Methods for handling single spreadsheet id 20 | inline const char *getSpreadsheetId() { return m_spreadsheetId.c_str(); } 21 | 22 | // Create a new spreadsheet and return the id 23 | const char *newSpreadsheet(const char *spreadsheetName, const char *parentId); 24 | inline const char *newSpreadsheet(const String &spreadsheetName, const String &parentId) 25 | { 26 | return newSpreadsheet(spreadsheetName.c_str(), parentId.c_str()); 27 | } 28 | 29 | // Create a new sheet (in spreadsheet) and return the id (-1 on fail) 30 | int32_t newSheet(const char *sheetName, const char *spreadsheetId); 31 | 32 | // Check if sheetName is in spreadsheet and return sheet ID (0 is the first sheet created by default) 33 | int32_t getSheetId(const char *sheetName, const char *spreadsheetId); 34 | 35 | // Set new title for a specific sheet inside a spreadsheet 36 | bool setSheetTitle(const char *sheetTitle, const char *spreadsheetId, int32_t sheetId = 0); 37 | 38 | // Append row to the spreadsheet 39 | bool appendRowToSheet(const char *spreadsheetId, const char *range, const char *row); 40 | inline bool appendRowToSheet(const String &spreadsheetId, const String &range, const String &row) 41 | { 42 | return appendRowToSheet(spreadsheetId.c_str(), range.c_str(), row.c_str()); 43 | } 44 | 45 | // Check if the spreadsheet is present in Google Drive 46 | const char* isSpreadSheet(const char *spreadsheetName, const char* parentName, bool createFolder = true); 47 | inline const char* isSpreadSheet(const String &spreadsheetName, const String &parentName, bool createFolder = true) 48 | { 49 | return isSpreadSheet(spreadsheetName.c_str(), parentName.c_str(), createFolder); 50 | } 51 | 52 | // Return the id of spreadsheet parent folder 53 | const char* getParentId() { 54 | return m_parentId.c_str(); 55 | } 56 | 57 | bool updateSheetList(String &query); 58 | 59 | private: 60 | String m_spreadsheetId; 61 | String m_parentId; 62 | 63 | // Class specialized parser 64 | bool readSheetClient(const int filter, const char *keyword = nullptr); 65 | bool parsePayload(const String &payload, const int filter, const char *gFile); 66 | }; 67 | #endif 68 | -------------------------------------------------------------------------------- /src/SerialLog.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | // Windows 10 | #define __FILE_NAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) 11 | 12 | // Linux, Mac 13 | // #define __FILE_NAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) 14 | 15 | #define _LOG_FORMAT(letter, format) "\n[" #letter "][%s:%u] %s():\t" format, __FILE_NAME__, __LINE__, __FUNCTION__ 16 | 17 | #if DEBUG_ENABLE 18 | #define log_debug(format, ...) Serial.printf(_LOG_FORMAT(D, format), ##__VA_ARGS__) 19 | #define log_error(format, ...) { Serial.println(); Serial.printf(_LOG_FORMAT(E, format), ##__VA_ARGS__); } 20 | #define log_info(format, ...) Serial.printf(_LOG_FORMAT(I, format), ##__VA_ARGS__) 21 | 22 | #define debugJson(X, Y) { Serial.println(); serializeJsonPretty(X, Y); Serial.println();} 23 | #define errorJson(E) { Serial.println(); Serial.println(E);} 24 | #else 25 | #define log_debug(format, ...) 26 | #define log_error(format, ...) 27 | #define log_info(format, ...) 28 | #define debugJson(X, Y) 29 | #define errorJson(E) 30 | #endif 31 | 32 | #if DEBUG_FUNCTION_CALL 33 | #ifdef ESP32 34 | #define functionLog() { \ 35 | Serial.printf("Heap memory %6d / %6d", heap_caps_get_free_size(0), heap_caps_get_largest_free_block(0));\ 36 | Serial.print("\t\t\t--- "); Serial.print(millis()); Serial.print("mS > "); Serial.print(__func__); Serial.println("()"); } 37 | #elif defined(ESP8266) 38 | #define functionLog() { \ 39 | uint32_t free; uint16_t max; uint8_t frag; ESP.getHeapStats(&free, &max, &frag); Serial.printf("free: %5d - max: %5d <- ", free, max);\ 40 | Serial.printf("[%s:%u]\t--- ", __FILE__, __LINE__); Serial.print(millis()); Serial.print("mS > "); Serial.print(__func__); Serial.println("()"); } 41 | #endif 42 | #else 43 | #define functionLog() 44 | #endif 45 | 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/zlib/README.md: -------------------------------------------------------------------------------- 1 | ZLIB DATA COMPRESSION LIBRARY 2 | 3 | zlib 1.2.12 is a general purpose data compression library. All the code is 4 | thread safe. The data format used by the zlib library is described by RFCs 5 | (Request for Comments) 1950 to 1952 in the files 6 | http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and 7 | rfc1952 (gzip format). 8 | 9 | All functions of the compression library are documented in the file zlib.h 10 | (volunteer to write man pages welcome, contact zlib@gzip.org). A usage example 11 | of the library is given in the file test/example.c which also tests that 12 | the library is working correctly. Another example is given in the file 13 | test/minigzip.c. The compression library itself is composed of all source 14 | files in the root directory. 15 | 16 | To compile all files and run the test program, follow the instructions given at 17 | the top of Makefile.in. In short "./configure; make test", and if that goes 18 | well, "make install" should work for most flavors of Unix. For Windows, use 19 | one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use 20 | make_vms.com. 21 | 22 | Questions about zlib should be sent to , or to Gilles Vollant 23 | for the Windows DLL version. The zlib home page is 24 | http://zlib.net/ . Before reporting a problem, please check this site to 25 | verify that you have the latest version of zlib; otherwise get the latest 26 | version and check whether the problem still exists or not. 27 | 28 | PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. 29 | 30 | Mark Nelson wrote an article about zlib for the Jan. 1997 31 | issue of Dr. Dobb's Journal; a copy of the article is available at 32 | http://marknelson.us/1997/01/01/zlib-engine/ . 33 | 34 | The changes made in version 1.2.12 are documented in the file ChangeLog. 35 | 36 | Unsupported third party contributions are provided in directory contrib/ . 37 | 38 | zlib is available in Java using the java.util.zip package, documented at 39 | http://java.sun.com/developer/technicalArticles/Programming/compression/ . 40 | 41 | A Perl interface to zlib written by Paul Marquess is available 42 | at CPAN (Comprehensive Perl Archive Network) sites, including 43 | http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . 44 | 45 | A Python interface to zlib written by A.M. Kuchling is 46 | available in Python 1.5 and later versions, see 47 | http://docs.python.org/library/zlib.html . 48 | 49 | zlib is built into tcl: http://wiki.tcl.tk/4610 . 50 | 51 | An experimental package to read and write files in .zip format, written on top 52 | of zlib by Gilles Vollant , is available in the 53 | contrib/minizip directory of zlib. 54 | 55 | 56 | Notes for some targets: 57 | 58 | - For Windows DLL versions, please see win32/DLL_FAQ.txt 59 | 60 | - For 64-bit Irix, deflate.c must be compiled without any optimization. With 61 | -O, one libpng test fails. The test works in 32 bit mode (with the -n32 62 | compiler flag). The compiler bug has been reported to SGI. 63 | 64 | - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works 65 | when compiled with cc. 66 | 67 | - On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is 68 | necessary to get gzprintf working correctly. This is done by configure. 69 | 70 | - zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with 71 | other compilers. Use "make test" to check your compiler. 72 | 73 | - gzdopen is not supported on RISCOS or BEOS. 74 | 75 | - For PalmOs, see http://palmzlib.sourceforge.net/ 76 | 77 | 78 | Acknowledgments: 79 | 80 | The deflate format used by zlib was defined by Phil Katz. The deflate and 81 | zlib specifications were written by L. Peter Deutsch. Thanks to all the 82 | people who reported problems and suggested various improvements in zlib; they 83 | are too numerous to cite here. 84 | 85 | Copyright notice: 86 | 87 | (C) 1995-2022 Jean-loup Gailly and Mark Adler 88 | 89 | This software is provided 'as-is', without any express or implied 90 | warranty. In no event will the authors be held liable for any damages 91 | arising from the use of this software. 92 | 93 | Permission is granted to anyone to use this software for any purpose, 94 | including commercial applications, and to alter it and redistribute it 95 | freely, subject to the following restrictions: 96 | 97 | 1. The origin of this software must not be misrepresented; you must not 98 | claim that you wrote the original software. If you use this software 99 | in a product, an acknowledgment in the product documentation would be 100 | appreciated but is not required. 101 | 2. Altered source versions must be plainly marked as such, and must not be 102 | misrepresented as being the original software. 103 | 3. This notice may not be removed or altered from any source distribution. 104 | 105 | Jean-loup Gailly Mark Adler 106 | jloup@gzip.org madler@alumni.caltech.edu 107 | 108 | If you use the zlib library in a product, we would appreciate *not* receiving 109 | lengthy legal documents to sign. The sources are provided for free but without 110 | warranty of any kind. The library has been entirely written by Jean-loup 111 | Gailly and Mark Adler; it does not include third-party code. We make all 112 | contributions to and distributions of this project solely in our personal 113 | capacity, and are not conveying any rights to any intellectual property of 114 | any third parties. 115 | 116 | If you redistribute modified sources, we would appreciate that you include in 117 | the file ChangeLog history information documenting your changes. Please read 118 | the FAQ for more information on the distribution of modified source versions. 119 | -------------------------------------------------------------------------------- /src/zlib/adler32.c: -------------------------------------------------------------------------------- 1 | /* adler32.c -- compute the Adler-32 checksum of a data stream 2 | * Copyright (C) 1995-2011, 2016 Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* @(#) $Id$ */ 7 | 8 | #include "zutil.h" 9 | 10 | local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); 11 | 12 | #define BASE 65521U /* largest prime smaller than 65536 */ 13 | #define NMAX 5552 14 | /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ 15 | 16 | #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} 17 | #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); 18 | #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); 19 | #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); 20 | #define DO16(buf) DO8(buf,0); DO8(buf,8); 21 | 22 | /* use NO_DIVIDE if your processor does not do division in hardware -- 23 | try it both ways to see which is faster */ 24 | #ifdef NO_DIVIDE 25 | /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 26 | (thank you to John Reiser for pointing this out) */ 27 | # define CHOP(a) \ 28 | do { \ 29 | unsigned long tmp = a >> 16; \ 30 | a &= 0xffffUL; \ 31 | a += (tmp << 4) - tmp; \ 32 | } while (0) 33 | # define MOD28(a) \ 34 | do { \ 35 | CHOP(a); \ 36 | if (a >= BASE) a -= BASE; \ 37 | } while (0) 38 | # define MOD(a) \ 39 | do { \ 40 | CHOP(a); \ 41 | MOD28(a); \ 42 | } while (0) 43 | # define MOD63(a) \ 44 | do { /* this assumes a is not negative */ \ 45 | z_off64_t tmp = a >> 32; \ 46 | a &= 0xffffffffL; \ 47 | a += (tmp << 8) - (tmp << 5) + tmp; \ 48 | tmp = a >> 16; \ 49 | a &= 0xffffL; \ 50 | a += (tmp << 4) - tmp; \ 51 | tmp = a >> 16; \ 52 | a &= 0xffffL; \ 53 | a += (tmp << 4) - tmp; \ 54 | if (a >= BASE) a -= BASE; \ 55 | } while (0) 56 | #else 57 | # define MOD(a) a %= BASE 58 | # define MOD28(a) a %= BASE 59 | # define MOD63(a) a %= BASE 60 | #endif 61 | 62 | /* ========================================================================= */ 63 | uLong ZEXPORT adler32_z(adler, buf, len) 64 | uLong adler; 65 | const Bytef *buf; 66 | z_size_t len; 67 | { 68 | unsigned long sum2; 69 | unsigned n; 70 | 71 | /* split Adler-32 into component sums */ 72 | sum2 = (adler >> 16) & 0xffff; 73 | adler &= 0xffff; 74 | 75 | /* in case user likes doing a byte at a time, keep it fast */ 76 | if (len == 1) { 77 | adler += buf[0]; 78 | if (adler >= BASE) 79 | adler -= BASE; 80 | sum2 += adler; 81 | if (sum2 >= BASE) 82 | sum2 -= BASE; 83 | return adler | (sum2 << 16); 84 | } 85 | 86 | /* initial Adler-32 value (deferred check for len == 1 speed) */ 87 | if (buf == Z_NULL) 88 | return 1L; 89 | 90 | /* in case short lengths are provided, keep it somewhat fast */ 91 | if (len < 16) { 92 | while (len--) { 93 | adler += *buf++; 94 | sum2 += adler; 95 | } 96 | if (adler >= BASE) 97 | adler -= BASE; 98 | MOD28(sum2); /* only added so many BASE's */ 99 | return adler | (sum2 << 16); 100 | } 101 | 102 | /* do length NMAX blocks -- requires just one modulo operation */ 103 | while (len >= NMAX) { 104 | len -= NMAX; 105 | n = NMAX / 16; /* NMAX is divisible by 16 */ 106 | do { 107 | DO16(buf); /* 16 sums unrolled */ 108 | buf += 16; 109 | } while (--n); 110 | MOD(adler); 111 | MOD(sum2); 112 | } 113 | 114 | /* do remaining bytes (less than NMAX, still just one modulo) */ 115 | if (len) { /* avoid modulos if none remaining */ 116 | while (len >= 16) { 117 | len -= 16; 118 | DO16(buf); 119 | buf += 16; 120 | } 121 | while (len--) { 122 | adler += *buf++; 123 | sum2 += adler; 124 | } 125 | MOD(adler); 126 | MOD(sum2); 127 | } 128 | 129 | /* return recombined sums */ 130 | return adler | (sum2 << 16); 131 | } 132 | 133 | /* ========================================================================= */ 134 | uLong ZEXPORT adler32(adler, buf, len) 135 | uLong adler; 136 | const Bytef *buf; 137 | uInt len; 138 | { 139 | return adler32_z(adler, buf, len); 140 | } 141 | 142 | /* ========================================================================= */ 143 | local uLong adler32_combine_(adler1, adler2, len2) 144 | uLong adler1; 145 | uLong adler2; 146 | z_off64_t len2; 147 | { 148 | unsigned long sum1; 149 | unsigned long sum2; 150 | unsigned rem; 151 | 152 | /* for negative len, return invalid adler32 as a clue for debugging */ 153 | if (len2 < 0) 154 | return 0xffffffffUL; 155 | 156 | /* the derivation of this formula is left as an exercise for the reader */ 157 | MOD63(len2); /* assumes len2 >= 0 */ 158 | rem = (unsigned)len2; 159 | sum1 = adler1 & 0xffff; 160 | sum2 = rem * sum1; 161 | MOD(sum2); 162 | sum1 += (adler2 & 0xffff) + BASE - 1; 163 | sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; 164 | if (sum1 >= BASE) sum1 -= BASE; 165 | if (sum1 >= BASE) sum1 -= BASE; 166 | if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); 167 | if (sum2 >= BASE) sum2 -= BASE; 168 | return sum1 | (sum2 << 16); 169 | } 170 | 171 | /* ========================================================================= */ 172 | uLong ZEXPORT adler32_combine(adler1, adler2, len2) 173 | uLong adler1; 174 | uLong adler2; 175 | z_off_t len2; 176 | { 177 | return adler32_combine_(adler1, adler2, len2); 178 | } 179 | 180 | uLong ZEXPORT adler32_combine64(adler1, adler2, len2) 181 | uLong adler1; 182 | uLong adler2; 183 | z_off64_t len2; 184 | { 185 | return adler32_combine_(adler1, adler2, len2); 186 | } 187 | -------------------------------------------------------------------------------- /src/zlib/compress.c: -------------------------------------------------------------------------------- 1 | /* compress.c -- compress a memory buffer 2 | * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* @(#) $Id$ */ 7 | 8 | #define ZLIB_INTERNAL 9 | #include "zlib.h" 10 | 11 | /* =========================================================================== 12 | Compresses the source buffer into the destination buffer. The level 13 | parameter has the same meaning as in deflateInit. sourceLen is the byte 14 | length of the source buffer. Upon entry, destLen is the total size of the 15 | destination buffer, which must be at least 0.1% larger than sourceLen plus 16 | 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. 17 | 18 | compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough 19 | memory, Z_BUF_ERROR if there was not enough room in the output buffer, 20 | Z_STREAM_ERROR if the level parameter is invalid. 21 | */ 22 | int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) 23 | Bytef *dest; 24 | uLongf *destLen; 25 | const Bytef *source; 26 | uLong sourceLen; 27 | int level; 28 | { 29 | z_stream stream; 30 | int err; 31 | const uInt max = (uInt)-1; 32 | uLong left; 33 | 34 | left = *destLen; 35 | *destLen = 0; 36 | 37 | stream.zalloc = (alloc_func)0; 38 | stream.zfree = (free_func)0; 39 | stream.opaque = (voidpf)0; 40 | 41 | err = deflateInit(&stream, level); 42 | if (err != Z_OK) return err; 43 | 44 | stream.next_out = dest; 45 | stream.avail_out = 0; 46 | stream.next_in = (z_const Bytef *)source; 47 | stream.avail_in = 0; 48 | 49 | do { 50 | if (stream.avail_out == 0) { 51 | stream.avail_out = left > (uLong)max ? max : (uInt)left; 52 | left -= stream.avail_out; 53 | } 54 | if (stream.avail_in == 0) { 55 | stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; 56 | sourceLen -= stream.avail_in; 57 | } 58 | err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); 59 | } while (err == Z_OK); 60 | 61 | *destLen = stream.total_out; 62 | deflateEnd(&stream); 63 | return err == Z_STREAM_END ? Z_OK : err; 64 | } 65 | 66 | /* =========================================================================== 67 | */ 68 | int ZEXPORT compress (dest, destLen, source, sourceLen) 69 | Bytef *dest; 70 | uLongf *destLen; 71 | const Bytef *source; 72 | uLong sourceLen; 73 | { 74 | return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); 75 | } 76 | 77 | /* =========================================================================== 78 | If the default memLevel or windowBits for deflateInit() is changed, then 79 | this function needs to be updated. 80 | */ 81 | uLong ZEXPORT compressBound (sourceLen) 82 | uLong sourceLen; 83 | { 84 | return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 85 | (sourceLen >> 25) + 13; 86 | } 87 | -------------------------------------------------------------------------------- /src/zlib/gzclose.c: -------------------------------------------------------------------------------- 1 | /* gzclose.c -- zlib gzclose() function 2 | * Copyright (C) 2004, 2010 Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | #include "gzguts.h" 7 | 8 | /* gzclose() is in a separate file so that it is linked in only if it is used. 9 | That way the other gzclose functions can be used instead to avoid linking in 10 | unneeded compression or decompression routines. */ 11 | int ZEXPORT gzclose(file) 12 | gzFile file; 13 | { 14 | #ifndef NO_GZCOMPRESS 15 | gz_statep state; 16 | 17 | if (file == NULL) 18 | return Z_STREAM_ERROR; 19 | state = (gz_statep)file; 20 | 21 | return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); 22 | #else 23 | return gzclose_r(file); 24 | #endif 25 | } 26 | -------------------------------------------------------------------------------- /src/zlib/gzguts.h: -------------------------------------------------------------------------------- 1 | /* gzguts.h -- zlib internal header definitions for gz* operations 2 | * Copyright (C) 2004-2019 Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | #ifdef _LARGEFILE64_SOURCE 7 | # ifndef _LARGEFILE_SOURCE 8 | # define _LARGEFILE_SOURCE 1 9 | # endif 10 | # ifdef _FILE_OFFSET_BITS 11 | # undef _FILE_OFFSET_BITS 12 | # endif 13 | #endif 14 | 15 | #ifdef HAVE_HIDDEN 16 | # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) 17 | #else 18 | # define ZLIB_INTERNAL 19 | #endif 20 | 21 | #include 22 | #include "zlib.h" 23 | #ifdef STDC 24 | # include 25 | # include 26 | # include 27 | #endif 28 | 29 | #ifndef _POSIX_SOURCE 30 | # define _POSIX_SOURCE 31 | #endif 32 | #include 33 | 34 | #ifdef _WIN32 35 | # include 36 | #endif 37 | 38 | #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) 39 | # include 40 | #endif 41 | 42 | #if defined(_WIN32) 43 | # define WIDECHAR 44 | #endif 45 | 46 | #ifdef WINAPI_FAMILY 47 | # define open _open 48 | # define read _read 49 | # define write _write 50 | # define close _close 51 | #endif 52 | 53 | #ifdef NO_DEFLATE /* for compatibility with old definition */ 54 | # define NO_GZCOMPRESS 55 | #endif 56 | 57 | #if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) 58 | # ifndef HAVE_VSNPRINTF 59 | # define HAVE_VSNPRINTF 60 | # endif 61 | #endif 62 | 63 | #if defined(__CYGWIN__) 64 | # ifndef HAVE_VSNPRINTF 65 | # define HAVE_VSNPRINTF 66 | # endif 67 | #endif 68 | 69 | #if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) 70 | # ifndef HAVE_VSNPRINTF 71 | # define HAVE_VSNPRINTF 72 | # endif 73 | #endif 74 | 75 | #ifndef HAVE_VSNPRINTF 76 | # ifdef MSDOS 77 | /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), 78 | but for now we just assume it doesn't. */ 79 | # define NO_vsnprintf 80 | # endif 81 | # ifdef __TURBOC__ 82 | # define NO_vsnprintf 83 | # endif 84 | # ifdef WIN32 85 | /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ 86 | # if !defined(vsnprintf) && !defined(NO_vsnprintf) 87 | # if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) 88 | # define vsnprintf _vsnprintf 89 | # endif 90 | # endif 91 | # endif 92 | # ifdef __SASC 93 | # define NO_vsnprintf 94 | # endif 95 | # ifdef VMS 96 | # define NO_vsnprintf 97 | # endif 98 | # ifdef __OS400__ 99 | # define NO_vsnprintf 100 | # endif 101 | # ifdef __MVS__ 102 | # define NO_vsnprintf 103 | # endif 104 | #endif 105 | 106 | /* unlike snprintf (which is required in C99), _snprintf does not guarantee 107 | null termination of the result -- however this is only used in gzlib.c where 108 | the result is assured to fit in the space provided */ 109 | #if defined(_MSC_VER) && _MSC_VER < 1900 110 | # define snprintf _snprintf 111 | #endif 112 | 113 | #ifndef local 114 | # define local static 115 | #endif 116 | /* since "static" is used to mean two completely different things in C, we 117 | define "local" for the non-static meaning of "static", for readability 118 | (compile with -Dlocal if your debugger can't find static symbols) */ 119 | 120 | /* gz* functions always use library allocation functions */ 121 | #ifndef STDC 122 | extern voidp malloc OF((uInt size)); 123 | extern void free OF((voidpf ptr)); 124 | #endif 125 | 126 | /* get errno and strerror definition */ 127 | #if defined UNDER_CE 128 | # include 129 | # define zstrerror() gz_strwinerror((DWORD)GetLastError()) 130 | #else 131 | # ifndef NO_STRERROR 132 | # include 133 | # define zstrerror() strerror(errno) 134 | # else 135 | # define zstrerror() "stdio error (consult errno)" 136 | # endif 137 | #endif 138 | 139 | /* provide prototypes for these when building zlib without LFS */ 140 | #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 141 | ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); 142 | ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); 143 | ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); 144 | ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); 145 | #endif 146 | 147 | /* default memLevel */ 148 | #if MAX_MEM_LEVEL >= 8 149 | # define DEF_MEM_LEVEL 8 150 | #else 151 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL 152 | #endif 153 | 154 | /* default i/o buffer size -- double this for output when reading (this and 155 | twice this must be able to fit in an unsigned type) */ 156 | #define GZBUFSIZE 8192 157 | 158 | /* gzip modes, also provide a little integrity check on the passed structure */ 159 | #define GZ_NONE 0 160 | #define GZ_READ 7247 161 | #define GZ_WRITE 31153 162 | #define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ 163 | 164 | /* values for gz_state how */ 165 | #define LOOK 0 /* look for a gzip header */ 166 | #define COPY 1 /* copy input directly */ 167 | #define GZIP 2 /* decompress a gzip stream */ 168 | 169 | /* internal gzip file state data structure */ 170 | typedef struct { 171 | /* exposed contents for gzgetc() macro */ 172 | struct gzFile_s x; /* "x" for exposed */ 173 | /* x.have: number of bytes available at x.next */ 174 | /* x.next: next output data to deliver or write */ 175 | /* x.pos: current position in uncompressed data */ 176 | /* used for both reading and writing */ 177 | int mode; /* see gzip modes above */ 178 | int fd; /* file descriptor */ 179 | char *path; /* path or fd for error messages */ 180 | unsigned size; /* buffer size, zero if not allocated yet */ 181 | unsigned want; /* requested buffer size, default is GZBUFSIZE */ 182 | unsigned char *in; /* input buffer (double-sized when writing) */ 183 | unsigned char *out; /* output buffer (double-sized when reading) */ 184 | int direct; /* 0 if processing gzip, 1 if transparent */ 185 | /* just for reading */ 186 | int how; /* 0: get header, 1: copy, 2: decompress */ 187 | z_off64_t start; /* where the gzip data started, for rewinding */ 188 | int eof; /* true if end of input file reached */ 189 | int past; /* true if read requested past end */ 190 | /* just for writing */ 191 | int level; /* compression level */ 192 | int strategy; /* compression strategy */ 193 | int reset; /* true if a reset is pending after a Z_FINISH */ 194 | /* seek request */ 195 | z_off64_t skip; /* amount to skip (already rewound if backwards) */ 196 | int seek; /* true if seek request pending */ 197 | /* error information */ 198 | int err; /* error code */ 199 | char *msg; /* error message */ 200 | /* zlib inflate or deflate stream */ 201 | z_stream strm; /* stream structure in-place (not a pointer) */ 202 | } gz_state; 203 | typedef gz_state FAR *gz_statep; 204 | 205 | /* shared functions */ 206 | void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); 207 | #if defined UNDER_CE 208 | char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); 209 | #endif 210 | 211 | /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t 212 | value -- needed when comparing unsigned to z_off64_t, which is signed 213 | (possible z_off64_t types off_t, off64_t, and long are all signed) */ 214 | #ifdef INT_MAX 215 | # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) 216 | #else 217 | unsigned ZLIB_INTERNAL gz_intmax OF((void)); 218 | # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) 219 | #endif 220 | -------------------------------------------------------------------------------- /src/zlib/inffast.h: -------------------------------------------------------------------------------- 1 | /* inffast.h -- header to use inffast.c 2 | * Copyright (C) 1995-2003, 2010 Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* WARNING: this file should *not* be used by applications. It is 7 | part of the implementation of the compression library and is 8 | subject to change. Applications should only use zlib.h. 9 | */ 10 | 11 | void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); 12 | -------------------------------------------------------------------------------- /src/zlib/inffixed.h: -------------------------------------------------------------------------------- 1 | /* inffixed.h -- table for decoding fixed codes 2 | * Generated automatically by makefixed(). 3 | */ 4 | 5 | /* WARNING: this file should *not* be used by applications. 6 | It is part of the implementation of this library and is 7 | subject to change. Applications should only use zlib.h. 8 | */ 9 | 10 | static const code lenfix[512] = { 11 | {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, 12 | {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, 13 | {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, 14 | {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, 15 | {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, 16 | {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, 17 | {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, 18 | {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, 19 | {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, 20 | {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, 21 | {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, 22 | {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, 23 | {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, 24 | {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, 25 | {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, 26 | {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, 27 | {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, 28 | {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, 29 | {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, 30 | {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, 31 | {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, 32 | {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, 33 | {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, 34 | {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, 35 | {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, 36 | {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, 37 | {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, 38 | {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, 39 | {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, 40 | {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, 41 | {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, 42 | {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, 43 | {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, 44 | {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, 45 | {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, 46 | {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, 47 | {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, 48 | {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, 49 | {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, 50 | {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, 51 | {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, 52 | {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, 53 | {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, 54 | {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, 55 | {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, 56 | {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, 57 | {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, 58 | {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, 59 | {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, 60 | {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, 61 | {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, 62 | {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, 63 | {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, 64 | {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, 65 | {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, 66 | {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, 67 | {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, 68 | {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, 69 | {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, 70 | {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, 71 | {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, 72 | {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, 73 | {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, 74 | {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, 75 | {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, 76 | {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, 77 | {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, 78 | {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, 79 | {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, 80 | {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, 81 | {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, 82 | {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, 83 | {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, 84 | {0,9,255} 85 | }; 86 | 87 | static const code distfix[32] = { 88 | {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, 89 | {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, 90 | {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, 91 | {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, 92 | {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, 93 | {22,5,193},{64,5,0} 94 | }; 95 | -------------------------------------------------------------------------------- /src/zlib/inflate.h: -------------------------------------------------------------------------------- 1 | /* inflate.h -- internal inflate state definition 2 | * Copyright (C) 1995-2019 Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* WARNING: this file should *not* be used by applications. It is 7 | part of the implementation of the compression library and is 8 | subject to change. Applications should only use zlib.h. 9 | */ 10 | 11 | /* define NO_GZIP when compiling if you want to disable gzip header and 12 | trailer decoding by inflate(). NO_GZIP would be used to avoid linking in 13 | the crc code when it is not needed. For shared libraries, gzip decoding 14 | should be left enabled. */ 15 | #ifndef NO_GZIP 16 | # define GUNZIP 17 | #endif 18 | 19 | /* Possible inflate modes between inflate() calls */ 20 | typedef enum { 21 | HEAD = 16180, /* i: waiting for magic header */ 22 | FLAGS, /* i: waiting for method and flags (gzip) */ 23 | TIME, /* i: waiting for modification time (gzip) */ 24 | OS, /* i: waiting for extra flags and operating system (gzip) */ 25 | EXLEN, /* i: waiting for extra length (gzip) */ 26 | EXTRA, /* i: waiting for extra bytes (gzip) */ 27 | NAME, /* i: waiting for end of file name (gzip) */ 28 | COMMENT, /* i: waiting for end of comment (gzip) */ 29 | HCRC, /* i: waiting for header crc (gzip) */ 30 | DICTID, /* i: waiting for dictionary check value */ 31 | DICT, /* waiting for inflateSetDictionary() call */ 32 | TYPE, /* i: waiting for type bits, including last-flag bit */ 33 | TYPEDO, /* i: same, but skip check to exit inflate on new block */ 34 | STORED, /* i: waiting for stored size (length and complement) */ 35 | COPY_, /* i/o: same as COPY below, but only first time in */ 36 | COPY, /* i/o: waiting for input or output to copy stored block */ 37 | TABLE, /* i: waiting for dynamic block table lengths */ 38 | LENLENS, /* i: waiting for code length code lengths */ 39 | CODELENS, /* i: waiting for length/lit and distance code lengths */ 40 | LEN_, /* i: same as LEN below, but only first time in */ 41 | LEN, /* i: waiting for length/lit/eob code */ 42 | LENEXT, /* i: waiting for length extra bits */ 43 | DIST, /* i: waiting for distance code */ 44 | DISTEXT, /* i: waiting for distance extra bits */ 45 | MATCH, /* o: waiting for output space to copy string */ 46 | LIT, /* o: waiting for output space to write literal */ 47 | CHECK, /* i: waiting for 32-bit check value */ 48 | LENGTH, /* i: waiting for 32-bit length (gzip) */ 49 | DONE, /* finished check, done -- remain here until reset */ 50 | BAD, /* got a data error -- remain here until reset */ 51 | MEM, /* got an inflate() memory error -- remain here until reset */ 52 | SYNC /* looking for synchronization bytes to restart inflate() */ 53 | } inflate_mode; 54 | 55 | /* 56 | State transitions between above modes - 57 | 58 | (most modes can go to BAD or MEM on error -- not shown for clarity) 59 | 60 | Process header: 61 | HEAD -> (gzip) or (zlib) or (raw) 62 | (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> 63 | HCRC -> TYPE 64 | (zlib) -> DICTID or TYPE 65 | DICTID -> DICT -> TYPE 66 | (raw) -> TYPEDO 67 | Read deflate blocks: 68 | TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK 69 | STORED -> COPY_ -> COPY -> TYPE 70 | TABLE -> LENLENS -> CODELENS -> LEN_ 71 | LEN_ -> LEN 72 | Read deflate codes in fixed or dynamic block: 73 | LEN -> LENEXT or LIT or TYPE 74 | LENEXT -> DIST -> DISTEXT -> MATCH -> LEN 75 | LIT -> LEN 76 | Process trailer: 77 | CHECK -> LENGTH -> DONE 78 | */ 79 | 80 | /* State maintained between inflate() calls -- approximately 7K bytes, not 81 | including the allocated sliding window, which is up to 32K bytes. */ 82 | struct inflate_state { 83 | z_streamp strm; /* pointer back to this zlib stream */ 84 | inflate_mode mode; /* current inflate mode */ 85 | int last; /* true if processing last block */ 86 | int wrap; /* bit 0 true for zlib, bit 1 true for gzip, 87 | bit 2 true to validate check value */ 88 | int havedict; /* true if dictionary provided */ 89 | int flags; /* gzip header method and flags, 0 if zlib, or 90 | -1 if raw or no header yet */ 91 | unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ 92 | unsigned long check; /* protected copy of check value */ 93 | unsigned long total; /* protected copy of output count */ 94 | gz_headerp head; /* where to save gzip header information */ 95 | /* sliding window */ 96 | unsigned wbits; /* log base 2 of requested window size */ 97 | unsigned wsize; /* window size or zero if not using window */ 98 | unsigned whave; /* valid bytes in the window */ 99 | unsigned wnext; /* window write index */ 100 | unsigned char FAR *window; /* allocated sliding window, if needed */ 101 | /* bit accumulator */ 102 | unsigned long hold; /* input bit accumulator */ 103 | unsigned bits; /* number of bits in "in" */ 104 | /* for string and stored block copying */ 105 | unsigned length; /* literal or length of data to copy */ 106 | unsigned offset; /* distance back to copy string from */ 107 | /* for table and code decoding */ 108 | unsigned extra; /* extra bits needed */ 109 | /* fixed and dynamic code tables */ 110 | code const FAR *lencode; /* starting table for length/literal codes */ 111 | code const FAR *distcode; /* starting table for distance codes */ 112 | unsigned lenbits; /* index bits for lencode */ 113 | unsigned distbits; /* index bits for distcode */ 114 | /* dynamic table building */ 115 | unsigned ncode; /* number of code length code lengths */ 116 | unsigned nlen; /* number of length code lengths */ 117 | unsigned ndist; /* number of distance code lengths */ 118 | unsigned have; /* number of code lengths in lens[] */ 119 | code FAR *next; /* next available space in codes[] */ 120 | unsigned short lens[320]; /* temporary storage for code lengths */ 121 | unsigned short work[288]; /* work area for code table building */ 122 | code codes[ENOUGH]; /* space for code tables */ 123 | int sane; /* if false, allow invalid distance too far */ 124 | int back; /* bits back of last unprocessed length/lit */ 125 | unsigned was; /* initial length of match */ 126 | }; 127 | -------------------------------------------------------------------------------- /src/zlib/inftrees.h: -------------------------------------------------------------------------------- 1 | /* inftrees.h -- header to use inftrees.c 2 | * Copyright (C) 1995-2005, 2010 Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* WARNING: this file should *not* be used by applications. It is 7 | part of the implementation of the compression library and is 8 | subject to change. Applications should only use zlib.h. 9 | */ 10 | 11 | /* Structure for decoding tables. Each entry provides either the 12 | information needed to do the operation requested by the code that 13 | indexed that table entry, or it provides a pointer to another 14 | table that indexes more bits of the code. op indicates whether 15 | the entry is a pointer to another table, a literal, a length or 16 | distance, an end-of-block, or an invalid code. For a table 17 | pointer, the low four bits of op is the number of index bits of 18 | that table. For a length or distance, the low four bits of op 19 | is the number of extra bits to get after the code. bits is 20 | the number of bits in this code or part of the code to drop off 21 | of the bit buffer. val is the actual byte to output in the case 22 | of a literal, the base length or distance, or the offset from 23 | the current table to the next table. Each entry is four bytes. */ 24 | typedef struct { 25 | unsigned char op; /* operation, extra bits, table bits */ 26 | unsigned char bits; /* bits in this part of the code */ 27 | unsigned short val; /* offset in table or code value */ 28 | } code; 29 | 30 | /* op values as set by inflate_table(): 31 | 00000000 - literal 32 | 0000tttt - table link, tttt != 0 is the number of table index bits 33 | 0001eeee - length or distance, eeee is the number of extra bits 34 | 01100000 - end of block 35 | 01000000 - invalid code 36 | */ 37 | 38 | /* Maximum size of the dynamic table. The maximum number of code structures is 39 | 1444, which is the sum of 852 for literal/length codes and 592 for distance 40 | codes. These values were found by exhaustive searches using the program 41 | examples/enough.c found in the zlib distribtution. The arguments to that 42 | program are the number of symbols, the initial root table size, and the 43 | maximum bit length of a code. "enough 286 9 15" for literal/length codes 44 | returns returns 852, and "enough 30 6 15" for distance codes returns 592. 45 | The initial root table size (9 or 6) is found in the fifth argument of the 46 | inflate_table() calls in inflate.c and infback.c. If the root table size is 47 | changed, then these maximum sizes would be need to be recalculated and 48 | updated. */ 49 | #define ENOUGH_LENS 852 50 | #define ENOUGH_DISTS 592 51 | #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) 52 | 53 | /* Type of code to build for inflate_table() */ 54 | typedef enum { 55 | CODES, 56 | LENS, 57 | DISTS 58 | } codetype; 59 | 60 | int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, 61 | unsigned codes, code FAR * FAR *table, 62 | unsigned FAR *bits, unsigned short FAR *work)); 63 | -------------------------------------------------------------------------------- /src/zlib/trees.h: -------------------------------------------------------------------------------- 1 | /* header created automatically with -DGEN_TREES_H */ 2 | 3 | local const ct_data static_ltree[L_CODES+2] = { 4 | {{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, 5 | {{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, 6 | {{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, 7 | {{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, 8 | {{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, 9 | {{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, 10 | {{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, 11 | {{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, 12 | {{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, 13 | {{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, 14 | {{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, 15 | {{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, 16 | {{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, 17 | {{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, 18 | {{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, 19 | {{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, 20 | {{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, 21 | {{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, 22 | {{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, 23 | {{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, 24 | {{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, 25 | {{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, 26 | {{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, 27 | {{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, 28 | {{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, 29 | {{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, 30 | {{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, 31 | {{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, 32 | {{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, 33 | {{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, 34 | {{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, 35 | {{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, 36 | {{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, 37 | {{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, 38 | {{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, 39 | {{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, 40 | {{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, 41 | {{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, 42 | {{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, 43 | {{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, 44 | {{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, 45 | {{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, 46 | {{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, 47 | {{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, 48 | {{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, 49 | {{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, 50 | {{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, 51 | {{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, 52 | {{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, 53 | {{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, 54 | {{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, 55 | {{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, 56 | {{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, 57 | {{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, 58 | {{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, 59 | {{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, 60 | {{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, 61 | {{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} 62 | }; 63 | 64 | local const ct_data static_dtree[D_CODES] = { 65 | {{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, 66 | {{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, 67 | {{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, 68 | {{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, 69 | {{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, 70 | {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} 71 | }; 72 | 73 | const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { 74 | 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 75 | 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 76 | 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 77 | 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 78 | 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 79 | 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 80 | 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 81 | 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 82 | 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 83 | 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 84 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 85 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86 | 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 87 | 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 88 | 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 89 | 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 90 | 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 91 | 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 92 | 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 93 | 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 94 | 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 95 | 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 96 | 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 97 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 98 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 99 | 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 100 | }; 101 | 102 | const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { 103 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 104 | 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 105 | 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 106 | 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 107 | 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 108 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 109 | 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 110 | 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 111 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 112 | 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 113 | 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 114 | 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 115 | 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 116 | }; 117 | 118 | local const int base_length[LENGTH_CODES] = { 119 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 120 | 64, 80, 96, 112, 128, 160, 192, 224, 0 121 | }; 122 | 123 | local const int base_dist[D_CODES] = { 124 | 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 125 | 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 126 | 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 127 | }; 128 | 129 | -------------------------------------------------------------------------------- /src/zlib/uncompr.c: -------------------------------------------------------------------------------- 1 | /* uncompr.c -- decompress a memory buffer 2 | * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* @(#) $Id$ */ 7 | 8 | #define ZLIB_INTERNAL 9 | #include "zlib.h" 10 | 11 | /* =========================================================================== 12 | Decompresses the source buffer into the destination buffer. *sourceLen is 13 | the byte length of the source buffer. Upon entry, *destLen is the total size 14 | of the destination buffer, which must be large enough to hold the entire 15 | uncompressed data. (The size of the uncompressed data must have been saved 16 | previously by the compressor and transmitted to the decompressor by some 17 | mechanism outside the scope of this compression library.) Upon exit, 18 | *destLen is the size of the decompressed data and *sourceLen is the number 19 | of source bytes consumed. Upon return, source + *sourceLen points to the 20 | first unused input byte. 21 | 22 | uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough 23 | memory, Z_BUF_ERROR if there was not enough room in the output buffer, or 24 | Z_DATA_ERROR if the input data was corrupted, including if the input data is 25 | an incomplete zlib stream. 26 | */ 27 | int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) 28 | Bytef *dest; 29 | uLongf *destLen; 30 | const Bytef *source; 31 | uLong *sourceLen; 32 | { 33 | z_stream stream; 34 | int err; 35 | const uInt max = (uInt)-1; 36 | uLong len, left; 37 | Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ 38 | 39 | len = *sourceLen; 40 | if (*destLen) { 41 | left = *destLen; 42 | *destLen = 0; 43 | } 44 | else { 45 | left = 1; 46 | dest = buf; 47 | } 48 | 49 | stream.next_in = (z_const Bytef *)source; 50 | stream.avail_in = 0; 51 | stream.zalloc = (alloc_func)0; 52 | stream.zfree = (free_func)0; 53 | stream.opaque = (voidpf)0; 54 | 55 | err = inflateInit(&stream); 56 | if (err != Z_OK) return err; 57 | 58 | stream.next_out = dest; 59 | stream.avail_out = 0; 60 | 61 | do { 62 | if (stream.avail_out == 0) { 63 | stream.avail_out = left > (uLong)max ? max : (uInt)left; 64 | left -= stream.avail_out; 65 | } 66 | if (stream.avail_in == 0) { 67 | stream.avail_in = len > (uLong)max ? max : (uInt)len; 68 | len -= stream.avail_in; 69 | } 70 | err = inflate(&stream, Z_NO_FLUSH); 71 | } while (err == Z_OK); 72 | 73 | *sourceLen -= len + stream.avail_in; 74 | if (dest != buf) 75 | *destLen = stream.total_out; 76 | else if (stream.total_out && err == Z_BUF_ERROR) 77 | left = 1; 78 | 79 | inflateEnd(&stream); 80 | return err == Z_STREAM_END ? Z_OK : 81 | err == Z_NEED_DICT ? Z_DATA_ERROR : 82 | err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : 83 | err; 84 | } 85 | 86 | int ZEXPORT uncompress (dest, destLen, source, sourceLen) 87 | Bytef *dest; 88 | uLongf *destLen; 89 | const Bytef *source; 90 | uLong sourceLen; 91 | { 92 | return uncompress2(dest, destLen, source, &sourceLen); 93 | } 94 | -------------------------------------------------------------------------------- /src/zlib/zlib.3: -------------------------------------------------------------------------------- 1 | .TH ZLIB 3 "15 Jan 2017" 2 | .SH NAME 3 | zlib \- compression/decompression library 4 | .SH SYNOPSIS 5 | [see 6 | .I zlib.h 7 | for full description] 8 | .SH DESCRIPTION 9 | The 10 | .I zlib 11 | library is a general purpose data compression library. 12 | The code is thread safe, assuming that the standard library functions 13 | used are thread safe, such as memory allocation routines. 14 | It provides in-memory compression and decompression functions, 15 | including integrity checks of the uncompressed data. 16 | This version of the library supports only one compression method (deflation) 17 | but other algorithms may be added later 18 | with the same stream interface. 19 | .LP 20 | Compression can be done in a single step if the buffers are large enough 21 | or can be done by repeated calls of the compression function. 22 | In the latter case, 23 | the application must provide more input and/or consume the output 24 | (providing more output space) before each call. 25 | .LP 26 | The library also supports reading and writing files in 27 | .IR gzip (1) 28 | (.gz) format 29 | with an interface similar to that of stdio. 30 | .LP 31 | The library does not install any signal handler. 32 | The decoder checks the consistency of the compressed data, 33 | so the library should never crash even in the case of corrupted input. 34 | .LP 35 | All functions of the compression library are documented in the file 36 | .IR zlib.h . 37 | The distribution source includes examples of use of the library 38 | in the files 39 | .I test/example.c 40 | and 41 | .IR test/minigzip.c, 42 | as well as other examples in the 43 | .IR examples/ 44 | directory. 45 | .LP 46 | Changes to this version are documented in the file 47 | .I ChangeLog 48 | that accompanies the source. 49 | .LP 50 | .I zlib 51 | is built in to many languages and operating systems, including but not limited to 52 | Java, Python, .NET, PHP, Perl, Ruby, Swift, and Go. 53 | .LP 54 | An experimental package to read and write files in the .zip format, 55 | written on top of 56 | .I zlib 57 | by Gilles Vollant (info@winimage.com), 58 | is available at: 59 | .IP 60 | http://www.winimage.com/zLibDll/minizip.html 61 | and also in the 62 | .I contrib/minizip 63 | directory of the main 64 | .I zlib 65 | source distribution. 66 | .SH "SEE ALSO" 67 | The 68 | .I zlib 69 | web site can be found at: 70 | .IP 71 | http://zlib.net/ 72 | .LP 73 | The data format used by the 74 | .I zlib 75 | library is described by RFC 76 | (Request for Comments) 1950 to 1952 in the files: 77 | .IP 78 | http://tools.ietf.org/html/rfc1950 (for the zlib header and trailer format) 79 | .br 80 | http://tools.ietf.org/html/rfc1951 (for the deflate compressed data format) 81 | .br 82 | http://tools.ietf.org/html/rfc1952 (for the gzip header and trailer format) 83 | .LP 84 | Mark Nelson wrote an article about 85 | .I zlib 86 | for the Jan. 1997 issue of Dr. Dobb's Journal; 87 | a copy of the article is available at: 88 | .IP 89 | http://marknelson.us/1997/01/01/zlib-engine/ 90 | .SH "REPORTING PROBLEMS" 91 | Before reporting a problem, 92 | please check the 93 | .I zlib 94 | web site to verify that you have the latest version of 95 | .IR zlib ; 96 | otherwise, 97 | obtain the latest version and see if the problem still exists. 98 | Please read the 99 | .I zlib 100 | FAQ at: 101 | .IP 102 | http://zlib.net/zlib_faq.html 103 | .LP 104 | before asking for help. 105 | Send questions and/or comments to zlib@gzip.org, 106 | or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). 107 | .SH AUTHORS AND LICENSE 108 | Version 1.2.11 109 | .LP 110 | Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler 111 | .LP 112 | This software is provided 'as-is', without any express or implied 113 | warranty. In no event will the authors be held liable for any damages 114 | arising from the use of this software. 115 | .LP 116 | Permission is granted to anyone to use this software for any purpose, 117 | including commercial applications, and to alter it and redistribute it 118 | freely, subject to the following restrictions: 119 | .LP 120 | .nr step 1 1 121 | .IP \n[step]. 3 122 | The origin of this software must not be misrepresented; you must not 123 | claim that you wrote the original software. If you use this software 124 | in a product, an acknowledgment in the product documentation would be 125 | appreciated but is not required. 126 | .IP \n+[step]. 127 | Altered source versions must be plainly marked as such, and must not be 128 | misrepresented as being the original software. 129 | .IP \n+[step]. 130 | This notice may not be removed or altered from any source distribution. 131 | .LP 132 | Jean-loup Gailly Mark Adler 133 | .br 134 | jloup@gzip.org madler@alumni.caltech.edu 135 | .LP 136 | The deflate format used by 137 | .I zlib 138 | was defined by Phil Katz. 139 | The deflate and 140 | .I zlib 141 | specifications were written by L. Peter Deutsch. 142 | Thanks to all the people who reported problems and suggested various 143 | improvements in 144 | .IR zlib ; 145 | who are too numerous to cite here. 146 | .LP 147 | UNIX manual page by R. P. C. Rodgers, 148 | U.S. National Library of Medicine (rodgers@nlm.nih.gov). 149 | .\" end of man page 150 | -------------------------------------------------------------------------------- /src/zlib/zlib.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/src/zlib/zlib.zip -------------------------------------------------------------------------------- /src/zlib/zutil.c: -------------------------------------------------------------------------------- 1 | /* zutil.c -- target dependent utility functions for the compression library 2 | * Copyright (C) 1995-2017 Jean-loup Gailly 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* @(#) $Id$ */ 7 | 8 | #include "zutil.h" 9 | #ifndef Z_SOLO 10 | # include "gzguts.h" 11 | #endif 12 | 13 | z_const char * const z_errmsg[10] = { 14 | (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ 15 | (z_const char *)"stream end", /* Z_STREAM_END 1 */ 16 | (z_const char *)"", /* Z_OK 0 */ 17 | (z_const char *)"file error", /* Z_ERRNO (-1) */ 18 | (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ 19 | (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ 20 | (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ 21 | (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ 22 | (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ 23 | (z_const char *)"" 24 | }; 25 | 26 | 27 | const char * ZEXPORT zlibVersion() 28 | { 29 | return ZLIB_VERSION; 30 | } 31 | 32 | uLong ZEXPORT zlibCompileFlags() 33 | { 34 | uLong flags; 35 | 36 | flags = 0; 37 | switch ((int)(sizeof(uInt))) { 38 | case 2: break; 39 | case 4: flags += 1; break; 40 | case 8: flags += 2; break; 41 | default: flags += 3; 42 | } 43 | switch ((int)(sizeof(uLong))) { 44 | case 2: break; 45 | case 4: flags += 1 << 2; break; 46 | case 8: flags += 2 << 2; break; 47 | default: flags += 3 << 2; 48 | } 49 | switch ((int)(sizeof(voidpf))) { 50 | case 2: break; 51 | case 4: flags += 1 << 4; break; 52 | case 8: flags += 2 << 4; break; 53 | default: flags += 3 << 4; 54 | } 55 | switch ((int)(sizeof(z_off_t))) { 56 | case 2: break; 57 | case 4: flags += 1 << 6; break; 58 | case 8: flags += 2 << 6; break; 59 | default: flags += 3 << 6; 60 | } 61 | #ifdef ZLIB_DEBUG 62 | flags += 1 << 8; 63 | #endif 64 | #if defined(ASMV) || defined(ASMINF) 65 | flags += 1 << 9; 66 | #endif 67 | #ifdef ZLIB_WINAPI 68 | flags += 1 << 10; 69 | #endif 70 | #ifdef BUILDFIXED 71 | flags += 1 << 12; 72 | #endif 73 | #ifdef DYNAMIC_CRC_TABLE 74 | flags += 1 << 13; 75 | #endif 76 | #ifdef NO_GZCOMPRESS 77 | flags += 1L << 16; 78 | #endif 79 | #ifdef NO_GZIP 80 | flags += 1L << 17; 81 | #endif 82 | #ifdef PKZIP_BUG_WORKAROUND 83 | flags += 1L << 20; 84 | #endif 85 | #ifdef FASTEST 86 | flags += 1L << 21; 87 | #endif 88 | #if defined(STDC) || defined(Z_HAVE_STDARG_H) 89 | # ifdef NO_vsnprintf 90 | flags += 1L << 25; 91 | # ifdef HAS_vsprintf_void 92 | flags += 1L << 26; 93 | # endif 94 | # else 95 | # ifdef HAS_vsnprintf_void 96 | flags += 1L << 26; 97 | # endif 98 | # endif 99 | #else 100 | flags += 1L << 24; 101 | # ifdef NO_snprintf 102 | flags += 1L << 25; 103 | # ifdef HAS_sprintf_void 104 | flags += 1L << 26; 105 | # endif 106 | # else 107 | # ifdef HAS_snprintf_void 108 | flags += 1L << 26; 109 | # endif 110 | # endif 111 | #endif 112 | return flags; 113 | } 114 | 115 | #ifdef ZLIB_DEBUG 116 | #include 117 | # ifndef verbose 118 | # define verbose 0 119 | # endif 120 | int ZLIB_INTERNAL z_verbose = verbose; 121 | 122 | void ZLIB_INTERNAL z_error (m) 123 | char *m; 124 | { 125 | fprintf(stderr, "%s\n", m); 126 | exit(1); 127 | } 128 | #endif 129 | 130 | /* exported to allow conversion of error code to string for compress() and 131 | * uncompress() 132 | */ 133 | const char * ZEXPORT zError(err) 134 | int err; 135 | { 136 | return ERR_MSG(err); 137 | } 138 | 139 | #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 140 | /* The older Microsoft C Run-Time Library for Windows CE doesn't have 141 | * errno. We define it as a global variable to simplify porting. 142 | * Its value is always 0 and should not be used. 143 | */ 144 | int errno = 0; 145 | #endif 146 | 147 | #ifndef HAVE_MEMCPY 148 | 149 | void ZLIB_INTERNAL zmemcpy(dest, source, len) 150 | Bytef* dest; 151 | const Bytef* source; 152 | uInt len; 153 | { 154 | if (len == 0) return; 155 | do { 156 | *dest++ = *source++; /* ??? to be unrolled */ 157 | } while (--len != 0); 158 | } 159 | 160 | int ZLIB_INTERNAL zmemcmp(s1, s2, len) 161 | const Bytef* s1; 162 | const Bytef* s2; 163 | uInt len; 164 | { 165 | uInt j; 166 | 167 | for (j = 0; j < len; j++) { 168 | if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; 169 | } 170 | return 0; 171 | } 172 | 173 | void ZLIB_INTERNAL zmemzero(dest, len) 174 | Bytef* dest; 175 | uInt len; 176 | { 177 | if (len == 0) return; 178 | do { 179 | *dest++ = 0; /* ??? to be unrolled */ 180 | } while (--len != 0); 181 | } 182 | #endif 183 | 184 | #ifndef Z_SOLO 185 | 186 | #ifdef SYS16BIT 187 | 188 | #ifdef __TURBOC__ 189 | /* Turbo C in 16-bit mode */ 190 | 191 | # define MY_ZCALLOC 192 | 193 | /* Turbo C malloc() does not allow dynamic allocation of 64K bytes 194 | * and farmalloc(64K) returns a pointer with an offset of 8, so we 195 | * must fix the pointer. Warning: the pointer must be put back to its 196 | * original form in order to free it, use zcfree(). 197 | */ 198 | 199 | #define MAX_PTR 10 200 | /* 10*64K = 640K */ 201 | 202 | local int next_ptr = 0; 203 | 204 | typedef struct ptr_table_s { 205 | voidpf org_ptr; 206 | voidpf new_ptr; 207 | } ptr_table; 208 | 209 | local ptr_table table[MAX_PTR]; 210 | /* This table is used to remember the original form of pointers 211 | * to large buffers (64K). Such pointers are normalized with a zero offset. 212 | * Since MSDOS is not a preemptive multitasking OS, this table is not 213 | * protected from concurrent access. This hack doesn't work anyway on 214 | * a protected system like OS/2. Use Microsoft C instead. 215 | */ 216 | 217 | voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) 218 | { 219 | voidpf buf; 220 | ulg bsize = (ulg)items*size; 221 | 222 | (void)opaque; 223 | 224 | /* If we allocate less than 65520 bytes, we assume that farmalloc 225 | * will return a usable pointer which doesn't have to be normalized. 226 | */ 227 | if (bsize < 65520L) { 228 | buf = farmalloc(bsize); 229 | if (*(ush*)&buf != 0) return buf; 230 | } else { 231 | buf = farmalloc(bsize + 16L); 232 | } 233 | if (buf == NULL || next_ptr >= MAX_PTR) return NULL; 234 | table[next_ptr].org_ptr = buf; 235 | 236 | /* Normalize the pointer to seg:0 */ 237 | *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; 238 | *(ush*)&buf = 0; 239 | table[next_ptr++].new_ptr = buf; 240 | return buf; 241 | } 242 | 243 | void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) 244 | { 245 | int n; 246 | 247 | (void)opaque; 248 | 249 | if (*(ush*)&ptr != 0) { /* object < 64K */ 250 | farfree(ptr); 251 | return; 252 | } 253 | /* Find the original pointer */ 254 | for (n = 0; n < next_ptr; n++) { 255 | if (ptr != table[n].new_ptr) continue; 256 | 257 | farfree(table[n].org_ptr); 258 | while (++n < next_ptr) { 259 | table[n-1] = table[n]; 260 | } 261 | next_ptr--; 262 | return; 263 | } 264 | Assert(0, "zcfree: ptr not found"); 265 | } 266 | 267 | #endif /* __TURBOC__ */ 268 | 269 | 270 | #ifdef M_I86 271 | /* Microsoft C in 16-bit mode */ 272 | 273 | # define MY_ZCALLOC 274 | 275 | #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) 276 | # define _halloc halloc 277 | # define _hfree hfree 278 | #endif 279 | 280 | voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) 281 | { 282 | (void)opaque; 283 | return _halloc((long)items, size); 284 | } 285 | 286 | void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) 287 | { 288 | (void)opaque; 289 | _hfree(ptr); 290 | } 291 | 292 | #endif /* M_I86 */ 293 | 294 | #endif /* SYS16BIT */ 295 | 296 | 297 | #ifndef MY_ZCALLOC /* Any system without a special alloc function */ 298 | 299 | #ifndef STDC 300 | extern voidp malloc OF((uInt size)); 301 | extern voidp calloc OF((uInt items, uInt size)); 302 | extern void free OF((voidpf ptr)); 303 | #endif 304 | 305 | voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) 306 | voidpf opaque; 307 | unsigned items; 308 | unsigned size; 309 | { 310 | (void)opaque; 311 | return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : 312 | (voidpf)calloc(items, size); 313 | } 314 | 315 | void ZLIB_INTERNAL zcfree (opaque, ptr) 316 | voidpf opaque; 317 | voidpf ptr; 318 | { 319 | (void)opaque; 320 | free(ptr); 321 | } 322 | 323 | #endif /* MY_ZCALLOC */ 324 | 325 | #endif /* !Z_SOLO */ 326 | -------------------------------------------------------------------------------- /src/zlib/zutil.h: -------------------------------------------------------------------------------- 1 | /* zutil.h -- internal interface and configuration of the compression library 2 | * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* WARNING: this file should *not* be used by applications. It is 7 | part of the implementation of the compression library and is 8 | subject to change. Applications should only use zlib.h. 9 | */ 10 | 11 | /* @(#) $Id$ */ 12 | 13 | #ifndef ZUTIL_H 14 | #define ZUTIL_H 15 | 16 | #ifdef HAVE_HIDDEN 17 | # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) 18 | #else 19 | # define ZLIB_INTERNAL 20 | #endif 21 | 22 | #include "zlib.h" 23 | 24 | #if defined(STDC) && !defined(Z_SOLO) 25 | # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) 26 | # include 27 | # endif 28 | # include 29 | # include 30 | #endif 31 | 32 | #ifndef local 33 | # define local static 34 | #endif 35 | /* since "static" is used to mean two completely different things in C, we 36 | define "local" for the non-static meaning of "static", for readability 37 | (compile with -Dlocal if your debugger can't find static symbols) */ 38 | 39 | typedef unsigned char uch; 40 | typedef uch FAR uchf; 41 | typedef unsigned short ush; 42 | typedef ush FAR ushf; 43 | typedef unsigned long ulg; 44 | 45 | #if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) 46 | # include 47 | # if (ULONG_MAX == 0xffffffffffffffff) 48 | # define Z_U8 unsigned long 49 | # elif (ULLONG_MAX == 0xffffffffffffffff) 50 | # define Z_U8 unsigned long long 51 | # elif (UINT_MAX == 0xffffffffffffffff) 52 | # define Z_U8 unsigned 53 | # endif 54 | #endif 55 | 56 | extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ 57 | /* (size given to avoid silly warnings with Visual C++) */ 58 | 59 | #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] 60 | 61 | #define ERR_RETURN(strm,err) \ 62 | return (strm->msg = ERR_MSG(err), (err)) 63 | /* To be used only when the state is known to be valid */ 64 | 65 | /* common constants */ 66 | 67 | #ifndef DEF_WBITS 68 | # define DEF_WBITS MAX_WBITS 69 | #endif 70 | /* default windowBits for decompression. MAX_WBITS is for compression only */ 71 | 72 | #if MAX_MEM_LEVEL >= 8 73 | # define DEF_MEM_LEVEL 8 74 | #else 75 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL 76 | #endif 77 | /* default memLevel */ 78 | 79 | #define STORED_BLOCK 0 80 | #define STATIC_TREES 1 81 | #define DYN_TREES 2 82 | /* The three kinds of block type */ 83 | 84 | #define MIN_MATCH 3 85 | #define MAX_MATCH 258 86 | /* The minimum and maximum match lengths */ 87 | 88 | #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ 89 | 90 | /* target dependencies */ 91 | 92 | #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) 93 | # define OS_CODE 0x00 94 | # ifndef Z_SOLO 95 | # if defined(__TURBOC__) || defined(__BORLANDC__) 96 | # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) 97 | /* Allow compilation with ANSI keywords only enabled */ 98 | void _Cdecl farfree( void *block ); 99 | void *_Cdecl farmalloc( unsigned long nbytes ); 100 | # else 101 | # include 102 | # endif 103 | # else /* MSC or DJGPP */ 104 | # include 105 | # endif 106 | # endif 107 | #endif 108 | 109 | #ifdef AMIGA 110 | # define OS_CODE 1 111 | #endif 112 | 113 | #if defined(VAXC) || defined(VMS) 114 | # define OS_CODE 2 115 | # define F_OPEN(name, mode) \ 116 | fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") 117 | #endif 118 | 119 | #ifdef __370__ 120 | # if __TARGET_LIB__ < 0x20000000 121 | # define OS_CODE 4 122 | # elif __TARGET_LIB__ < 0x40000000 123 | # define OS_CODE 11 124 | # else 125 | # define OS_CODE 8 126 | # endif 127 | #endif 128 | 129 | #if defined(ATARI) || defined(atarist) 130 | # define OS_CODE 5 131 | #endif 132 | 133 | #ifdef OS2 134 | # define OS_CODE 6 135 | # if defined(M_I86) && !defined(Z_SOLO) 136 | # include 137 | # endif 138 | #endif 139 | 140 | #if defined(MACOS) || defined(TARGET_OS_MAC) 141 | # define OS_CODE 7 142 | # ifndef Z_SOLO 143 | # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os 144 | # include /* for fdopen */ 145 | # else 146 | # ifndef fdopen 147 | # define fdopen(fd,mode) NULL /* No fdopen() */ 148 | # endif 149 | # endif 150 | # endif 151 | #endif 152 | 153 | #ifdef __acorn 154 | # define OS_CODE 13 155 | #endif 156 | 157 | #if defined(WIN32) && !defined(__CYGWIN__) 158 | # define OS_CODE 10 159 | #endif 160 | 161 | #ifdef _BEOS_ 162 | # define OS_CODE 16 163 | #endif 164 | 165 | #ifdef __TOS_OS400__ 166 | # define OS_CODE 18 167 | #endif 168 | 169 | #ifdef __APPLE__ 170 | # define OS_CODE 19 171 | #endif 172 | 173 | #if defined(_BEOS_) || defined(RISCOS) 174 | # define fdopen(fd,mode) NULL /* No fdopen() */ 175 | #endif 176 | 177 | #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX 178 | # if defined(_WIN32_WCE) 179 | # define fdopen(fd,mode) NULL /* No fdopen() */ 180 | # else 181 | # define fdopen(fd,type) _fdopen(fd,type) 182 | # endif 183 | #endif 184 | 185 | #if defined(__BORLANDC__) && !defined(MSDOS) 186 | #pragma warn -8004 187 | #pragma warn -8008 188 | #pragma warn -8066 189 | #endif 190 | 191 | /* provide prototypes for these when building zlib without LFS */ 192 | #if !defined(_WIN32) && \ 193 | (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) 194 | ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); 195 | ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); 196 | #endif 197 | 198 | /* common defaults */ 199 | 200 | #ifndef OS_CODE 201 | # define OS_CODE 3 /* assume Unix */ 202 | #endif 203 | 204 | #ifndef F_OPEN 205 | # define F_OPEN(name, mode) fopen((name), (mode)) 206 | #endif 207 | 208 | /* functions */ 209 | 210 | #if defined(pyr) || defined(Z_SOLO) 211 | # define NO_MEMCPY 212 | #endif 213 | #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) 214 | /* Use our own functions for small and medium model with MSC <= 5.0. 215 | * You may have to use the same strategy for Borland C (untested). 216 | * The __SC__ check is for Symantec. 217 | */ 218 | # define NO_MEMCPY 219 | #endif 220 | #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) 221 | # define HAVE_MEMCPY 222 | #endif 223 | #ifdef HAVE_MEMCPY 224 | # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ 225 | # define zmemcpy _fmemcpy 226 | # define zmemcmp _fmemcmp 227 | # define zmemzero(dest, len) _fmemset(dest, 0, len) 228 | # else 229 | # define zmemcpy memcpy 230 | # define zmemcmp memcmp 231 | # define zmemzero(dest, len) memset(dest, 0, len) 232 | # endif 233 | #else 234 | void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); 235 | int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); 236 | void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); 237 | #endif 238 | 239 | /* Diagnostic functions */ 240 | #ifdef ZLIB_DEBUG 241 | # include 242 | extern int ZLIB_INTERNAL z_verbose; 243 | extern void ZLIB_INTERNAL z_error OF((char *m)); 244 | # define Assert(cond,msg) {if(!(cond)) z_error(msg);} 245 | # define Trace(x) {if (z_verbose>=0) fprintf x ;} 246 | # define Tracev(x) {if (z_verbose>0) fprintf x ;} 247 | # define Tracevv(x) {if (z_verbose>1) fprintf x ;} 248 | # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} 249 | # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} 250 | #else 251 | # define Assert(cond,msg) 252 | # define Trace(x) 253 | # define Tracev(x) 254 | # define Tracevv(x) 255 | # define Tracec(c,x) 256 | # define Tracecv(c,x) 257 | #endif 258 | 259 | #ifndef Z_SOLO 260 | voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, 261 | unsigned size)); 262 | void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); 263 | #endif 264 | 265 | #define ZALLOC(strm, items, size) \ 266 | (*((strm)->zalloc))((strm)->opaque, (items), (size)) 267 | #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) 268 | #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} 269 | 270 | /* Reverse the bytes in a 32-bit value */ 271 | #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ 272 | (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) 273 | 274 | #endif /* ZUTIL_H */ 275 | -------------------------------------------------------------------------------- /token_helper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/token_helper.png -------------------------------------------------------------------------------- /ui/README.md: -------------------------------------------------------------------------------- 1 | Integrated webserver user interface (Vue project) 2 | -------------------------------------------------------------------------------- /ui/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /ui/finalize.js: -------------------------------------------------------------------------------- 1 | // Finalize Nodejs Script 2 | // 1 - Append JS in HTML Document 3 | // 2 - Gzip HTML 4 | // 3 - Covert to Raw Bytes 5 | // 4 - ( Save to File: webpage.h ) in dist Folder 6 | 7 | const fs = require('fs'); 8 | const { gzip } = require('@gfx/zopfli'); 9 | 10 | function getByteArray(file){ 11 | let fileData = file.toString('hex'); 12 | let result = []; 13 | for (let i = 0; i < fileData.length; i+=2) 14 | result.push('0x'+fileData[i]+''+fileData[i+1]); 15 | return result; 16 | } 17 | 18 | let js = fs.readFileSync(__dirname+'/dist/js/app.js'); 19 | let html = ` 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Arduino Google API 28 | 29 | 30 | 33 |
34 | 35 | 36 | 37 | `; 38 | // Gzip the index.html file with JS Code. 39 | // const gzippedIndex = zlib.gzipSync(html, {'level': zlib.constants.Z_BEST_COMPRESSION}); 40 | // let indexHTML = getByteArray(gzippedIndex); 41 | 42 | // let source = 43 | // ` 44 | // const uint32_t WEBPAGE_HTML_SIZE = ${indexHTML.length}; 45 | // const char WEBPAGE_HTML[] PROGMEM = { ${indexHTML} }; 46 | // `; 47 | // fs.writeFileSync(__dirname+'/dist/webpage.h', source, 'utf8'); 48 | 49 | // Produce a second variant with zopfli (a improved zip algorithm by google) 50 | // Takes much more time and maybe is not available on every machine 51 | const input = html; 52 | gzip(input, {numiterations: 15}, (err, output) => { 53 | indexHTML = output; 54 | let source = 55 | ` 56 | const uint32_t AUTHPAGE_HTML_SIZE = ${indexHTML.length}; 57 | const char AUTHPAGE_HTML[] PROGMEM = { ${indexHTML} }; 58 | `; 59 | 60 | fs.writeFileSync(__dirname + '/dist/ga_config.h', source, 'utf8'); 61 | // fs.writeFileSync('../Arduino-Google-API/src/WebServer/setup_htm.h', source, 'utf8'); 62 | 63 | }); 64 | -------------------------------------------------------------------------------- /ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@gfx/zopfli": "^1.0.14", 12 | "@popperjs/core": "^2.6.0", 13 | "airbnb": "0.0.2", 14 | "axios": "^0.21.1", 15 | "bootstrap": "^5.0.0-beta2", 16 | "bootstrap-vue": "^2.21.2", 17 | "core-js": "^3.6.5", 18 | "fontawesome": "^5.6.3", 19 | "googleapis": "^67.0.0", 20 | "http2": "^3.3.7", 21 | "mutationobserver-shim": "^0.3.7", 22 | "vue": "^2.6.11", 23 | "vue-browser-detect-plugin": "^0.1.13", 24 | "webpack-shell-plugin": "^0.5.0", 25 | "zlib": "^1.0.5" 26 | }, 27 | "devDependencies": { 28 | "@vue/cli-plugin-babel": "~4.5.0", 29 | "@vue/cli-plugin-eslint": "~4.5.0", 30 | "@vue/cli-service": "~4.5.0", 31 | "@vue/compiler-sfc": "^3.0.0-0", 32 | "@vue/eslint-config-airbnb": "^5.0.2", 33 | "archiver": "^5.2.0", 34 | "babel-eslint": "^10.1.0", 35 | "eslint": "^6.7.2", 36 | "eslint-plugin-vue": "^6.2.2", 37 | "less": "^4.1.1", 38 | "less-loader": "^8.0.0", 39 | "sass": "^1.26.11", 40 | "sass-loader": "^10.0.2", 41 | "vue-svg-loader": "^0.16.0", 42 | "vue-template-compiler": "^2.6.11", 43 | "webpack": "^4.0.0", 44 | "webpack-bundle-analyzer": "^4.4.1" 45 | }, 46 | "eslintConfig": { 47 | "root": true, 48 | "env": { 49 | "node": true 50 | }, 51 | "extends": [ 52 | "plugin:vue/essential", 53 | "eslint:recommended" 54 | ], 55 | "parserOptions": { 56 | "parser": "babel-eslint" 57 | }, 58 | "rules": { 59 | "no-unused-vars": "off" 60 | } 61 | }, 62 | "browserslist": [ 63 | "> 1%", 64 | "last 2 versions", 65 | "not dead" 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /ui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/ui/public/favicon.ico -------------------------------------------------------------------------------- /ui/public/gapi_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "redirect_uri": "https://enyi3pe1qxxxxz9.m.pipedream.net", 3 | "scope": "https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/spreadsheets", 4 | "api_key": "AIzaSyB-xxxxxxxxxxxxxxxxxxxxxxxxxxxx", 5 | "client_id": "xxxxxxxx-f9g6btf4ip5ge3guv944q01qvoa2srhf.apps.googleusercontent.com", 6 | "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxx" 7 | } 8 | -------------------------------------------------------------------------------- /ui/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Arduino Google API 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ui/public/ipaddress: -------------------------------------------------------------------------------- 1 | 2 | 192.168.249.2 -------------------------------------------------------------------------------- /ui/public/scan: -------------------------------------------------------------------------------- 1 | [{"ssid":"WOW FI - FASTWEB","strength":"-75","security":true},{"ssid":"PuccosNET","strength":"-84","security":true, "selected":true}] -------------------------------------------------------------------------------- /ui/readme.md: -------------------------------------------------------------------------------- 1 | Integrated webserver user interface (Vue project) 2 | -------------------------------------------------------------------------------- /ui/src/App.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 47 | 48 | 61 | -------------------------------------------------------------------------------- /ui/src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cotestatnt/Arduino-Google-API/2024105f82c7fa8117fe53a2e05d0f324bb87310/ui/src/assets/favicon.ico -------------------------------------------------------------------------------- /ui/src/assets/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ui/src/components/BModal.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 49 | 50 | -------------------------------------------------------------------------------- /ui/src/components/Token.vue: -------------------------------------------------------------------------------- 1 | 74 | 75 | 258 | 259 | 260 | 276 | -------------------------------------------------------------------------------- /ui/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | // import 'bootstrap'; 5 | import '@/scss/custom.scss'; 6 | Vue.config.productionTip = false 7 | 8 | new Vue({ 9 | render: h => h(App), 10 | }).$mount('#app') 11 | -------------------------------------------------------------------------------- /ui/src/scss/custom.scss: -------------------------------------------------------------------------------- 1 | // @import "node_modules/bootstrap/scss/bootstrap"; 2 | 3 | @import "node_modules/bootstrap/scss/_functions"; 4 | @import "node_modules/bootstrap/scss/_variables"; 5 | @import "node_modules/bootstrap/scss/_mixins"; 6 | @import "node_modules/bootstrap/scss/_utilities"; 7 | 8 | // Layout & components 9 | @import "node_modules/bootstrap/scss/_root"; 10 | // @import "node_modules/bootstrap/scss/_reboot"; 11 | // @import "node_modules/bootstrap/scss/_type"; 12 | // @import "node_modules/bootstrap/scss/_images"; 13 | 14 | @import "node_modules/bootstrap/scss/_containers"; 15 | // @import "node_modules/bootstrap/scss/_grid"; 16 | @import "node_modules/bootstrap/scss/_tables"; 17 | @import "node_modules/bootstrap/scss/_forms"; 18 | @import "node_modules/bootstrap/scss/_buttons"; 19 | // @import "node_modules/bootstrap/scss/_transitions"; 20 | // @import "node_modules/bootstrap/scss/_dropdown"; 21 | // @import "node_modules/bootstrap/scss/_button-group"; 22 | // @import "node_modules/bootstrap/scss/_nav"; 23 | // @import "node_modules/bootstrap/scss/_navbar"; 24 | // @import "node_modules/bootstrap/scss/_card"; 25 | // @import "node_modules/bootstrap/scss/_accordion"; 26 | // @import "node_modules/bootstrap/scss/_breadcrumb"; 27 | // @import "node_modules/bootstrap/scss/_pagination"; 28 | // @import "node_modules/bootstrap/scss/_badge"; 29 | @import "node_modules/bootstrap/scss/_alert"; 30 | // @import "node_modules/bootstrap/scss/_progress"; 31 | // @import "node_modules/bootstrap/scss/_list-group"; 32 | @import "node_modules/bootstrap/scss/_close"; 33 | // @import "node_modules/bootstrap/scss/_toasts"; 34 | @import "node_modules/bootstrap/scss/_modal"; 35 | // @import "node_modules/bootstrap/scss/_tooltip"; 36 | // @import "node_modules/bootstrap/scss/_popover"; 37 | // @import "node_modules/bootstrap/scss/_carousel"; 38 | // @import "node_modules/bootstrap/scss/_spinners"; 39 | 40 | // Helpers 41 | // @import "node_modules/bootstrap/scss/_helpers"; 42 | 43 | // // Utilities 44 | @import "node_modules/bootstrap/scss/utilities/_api"; 45 | // scss-docs-end import-stack 46 | -------------------------------------------------------------------------------- /ui/vue.config.js: -------------------------------------------------------------------------------- 1 | const WebpackShellPlugin = require('webpack-shell-plugin'); 2 | 3 | module.exports = { 4 | chainWebpack: (config) => { 5 | const svgRule = config.module.rule('svg'); 6 | svgRule.uses.clear(); 7 | svgRule 8 | .use('vue-loader') 9 | .loader('vue-loader') 10 | .end() 11 | .use('vue-svg-loader') 12 | .loader('vue-svg-loader'); 13 | }, 14 | 15 | pluginOptions: { 16 | 'style-resources-loader': { 17 | preProcessor: 'scss', 18 | patterns: [] 19 | } 20 | }, 21 | 22 | outputDir: undefined, 23 | assetsDir: undefined, 24 | runtimeCompiler: undefined, 25 | productionSourceMap: undefined, 26 | parallel: undefined, 27 | css: { extract: false }, 28 | filenameHashing: false, 29 | chainWebpack: config => { 30 | config.optimization.delete('splitChunks') 31 | }, 32 | configureWebpack: { 33 | plugins: [ 34 | new WebpackShellPlugin({ 35 | onBuildEnd: ['node finalize.js'] 36 | }), 37 | ] 38 | } 39 | } 40 | --------------------------------------------------------------------------------