qlic

Zoho Cliq but not really
git clone git@getsh.org:qlic.git
Log | Files | Refs | LICENSE

commit dfa6876fe79a49cbd2faaa2fb7250e346057d57f
parent 3014f4b315e5e0c40c015499b2e80e1728e1fd31
Author: Bharatvaj <bharatvaj@yahoo.com>
Date:   Wed, 20 Apr 2022 23:30:56 +0530

Add qlic_oauth.h

Add config.h for storing compile time values

Handle basic argument parsing for testing

Diffstat:
MMakefile | 4++--
Mcliq_apis.c | 9++++-----
Aconfig.h | 11+++++++++++
Aconfig.json | 6++++++
Mqlic.c | 37+++++++++++++++++++++++++++----------
Mqlic_common.c | 12++++++++----
Mqlic_common.h | 2+-
Aqlic_oauth.h | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mqlic_response_handler.c | 13++++++++++---
Mqlic_response_handler.h | 2+-
Mqlic_types.h | 2+-
Astate.json | 8++++++++
12 files changed, 170 insertions(+), 27 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,5 +1,5 @@ -qlic: qlic.c - $(CC) qlic.c qlic_response_handler.c qlic_common.c cliq_apis.c -o qlic -I. -lcurl -g +qlic: qlic.c qlic_response_handler.* qlic_common.* cliq_apis.* qlic_oauth.h + $(CC) qlic.c qlic_response_handler.c qlic_common.c cliq_apis.c -o qlic -I. -I${HOME}/sysroot/include -L${HOME}/sysroot/lib -lnxjson -loauth -lcurl -g test: qlic ./qlic -r diff --git a/cliq_apis.c b/cliq_apis.c @@ -3,13 +3,12 @@ #include <stdio.h> #include <stdlib.h> -#define __QLIC_SEND_MESSAGE_STR "https://cliq.zoho.com/api/v2/chats/%s/message" QlicString* qlic_send_message_str(QlicString* chat_id) { +#define __QLIC_SEND_MESSAGE_API_STR "https://cliq.zoho.com/api/v2/chats/%s/message" QlicString* send_message = init_qlic_string(); - // tenet moment // minus 2 for removing the format specifier :( - send_message->len = sizeof(__QLIC_SEND_MESSAGE_STR) + chat_id->len - 2; - send_message->string = (char*)malloc(send_message->len); - snprintf(send_message->string, send_message->len, __QLIC_SEND_MESSAGE_STR, chat_id->string); + send_message->len = sizeof(__QLIC_SEND_MESSAGE_API_STR) + chat_id->len - 2; + send_message->string = (char *)malloc(send_message->len * sizeof(char)); + snprintf(send_message->string, send_message->len, __QLIC_SEND_MESSAGE_API_STR, chat_id->string); return send_message; } diff --git a/config.h b/config.h @@ -0,0 +1,11 @@ +#ifndef __CLIQ_CONFIG_H +#define __CLIQ_CONFIG_H +#define CLIQ_AUTH_ENDPOINT "https://accounts.zoho.com/oauth/v2/auth" +#define CLIQ_TOKEN_ENDPOINT "https://accounts.zoho.com/oauth/v2/token" + +#define CLIQ_CLIENT_ID "" +#define CLIQ_CLIENT_SECRET "" +#define CLIQ_REDIRECT_URI "https://127.0.0.1:8443/hello" +#define CLIQ_SCOPE "ZohoCliq.Chats.READ,ZohoCliq.Messages.READ,ZohoCliq.Webhooks.CREATE" + +#endif diff --git a/config.json b/config.json @@ -0,0 +1,6 @@ +{ + "user_id": { + "client_id": "", + "client_secret": "" + } +} diff --git a/qlic.c b/qlic.c @@ -4,27 +4,44 @@ #include <qlic_common.h> #include <cliq_apis.h> #include <qlic_response_handler.h> +#include <qlic_oauth.h> +int qlic_send_text_msg(const char* __access_token, const char* __chat_id) { + QlicString* access_token = NULL; + access_token = init_qlic_string(); + access_token->len = strlen(__access_token); + access_token->string = (char*)malloc(access_token->len * sizeof(__access_token)); + strncpy(access_token->string, __access_token, access_token->len); + QlicContext* qlic_context = qlic_context_access_init(access_token); + if (qlic_context == NULL) { + qlic_error("Cannot init network library"); + return -1; + } + QlicString* chat_id = init_qlic_string(); + __QLIC_ASSIGN_STRING(chat_id, __chat_id); + qlic_context->request_url = qlic_send_message_str(chat_id); + qlic_request(qlic_context, qlic_handle_send_message, true); + return 0; +} // TODO Send error back -#define __QLIC_ACCESS_TOKEN "Zoho-oauthtoken " int main(int argc, char* argv[]) { - QlicString* access_token = init_qlic_string(); - __QLIC_ASSIGN_STRING(access_token, __QLIC_ACCESS_TOKEN); if (argc == 1) { qlic_error("Not enough arguments"); return -1; } + // TODO Use an argument parsing library if (strcmp(argv[1], "-r") == 0) { - QlicContext* qlic_context = qlic_context_access_init(access_token); - if (qlic_context == NULL) { - qlic_error("Cannot init network library"); + // TODO read access_token from state.json + char* access_token = "1000.429cf5132d6cc978960bfdd6e0a425cc.80bbd5584b0c35133c4f82143e6811b2"; + // FIXME possible buffer overflow here + qlic_send_text_msg(access_token, argv[2]); + } else if (strcmp(argv[1], "-a") == 0) { + char* access_token = start_oauth_server(); + if (access_token == NULL) { + qlic_error("Access token is empty, authentication failed"); return -1; } - QlicString* chat_id = init_qlic_string(); - __QLIC_ASSIGN_STRING(chat_id, "2243227993181997558"); - qlic_context->request_url = qlic_send_message_str(chat_id); - qlic_request(qlic_context, qlic_handle_send_message, true); } return 0; } diff --git a/qlic_common.c b/qlic_common.c @@ -2,6 +2,7 @@ #include <curl/curl.h> #include <stdlib.h> #include <string.h> +#include <qlic_response_handler.h> void qlic_error(const char* error_message) { fprintf(stderr, error_message); @@ -13,8 +14,8 @@ static struct curl_slist* __qlic_set_request_headers(QlicContext* context, QlicS return NULL; } struct curl_slist* list = NULL; -#define __QLIC_AUTHORIZATION_HEADER "Authorization: " - // TODO cleanup authorization_header if curl doesn't handle it? +#define __QLIC_AUTHORIZATION_HEADER "Authorization: Zoho-oauthtoken " + // TODO free up authorization_header if curl doesn't handle size_t authorization_header_len = sizeof(__QLIC_AUTHORIZATION_HEADER) + access_token->len; char* authorization_header = (char*)malloc(authorization_header_len); strncpy(authorization_header, __QLIC_AUTHORIZATION_HEADER, sizeof(__QLIC_AUTHORIZATION_HEADER)); @@ -67,12 +68,15 @@ void qlic_request(QlicContext* context, qlic_response_callback callback, bool is CURL* curl = (CURL*)context->context; CURLcode res; curl_easy_setopt(curl, CURLOPT_URL, context->request_url->string); - /* curl_easy_setopt(curl, CURLOPT_GET, 1); */ /* curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); */ - curl_easy_setopt(curl, CURLOPT_READFUNCTION, callback); if (is_post_request) { curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"text\": \"Hi\"}"); } + /* curl_easy_setopt(curl, CURLOPT_READFUNCTION, qlic_handle_read_chat); */ + /* curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); */ + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl); res = curl_easy_perform(curl); if(res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", diff --git a/qlic_common.h b/qlic_common.h @@ -6,7 +6,7 @@ #define __QLIC_ASSIGN_STRING(X,Y) \ X->string = Y; \ - X->len = sizeof(Y); + X->len = strlen(Y); void qlic_error(const char* error_message); diff --git a/qlic_oauth.h b/qlic_oauth.h @@ -0,0 +1,91 @@ +#ifndef __QLIC_OAUTH_H +#define __QLIC_OAUTH_H + +#include <oauth2.h> +#include <stdio.h> +#include <config.h> +#include <nxjson.h> + +// TODO Choose between DB and text files for saving this information +// If using text, choose between formats, yaml or json or other format, which is more suckless +// If DB, sliqte3 is a good choice, but don't +// Going to need a json parser and writer, might as well make the config files as json as well +const char* saved_grant_token = NULL; +const char* saved_access_token = NULL; +/* const char* saved_grant_token = ""; */ + +/* const char* saved_access_token = ""; */ + +// TODO rethink this decision later, char* or const char* ? +// Have to free the returning string at the end, who does that? +char *json_access_code_transformer(char* str) { + const nx_json* json = nx_json_parse(str, nx_json_unicode_to_utf8); + if (json->type == NX_JSON_OBJECT) { + const nx_json* at = nx_json_get(json, "access_token"); + if (at->type == NX_JSON_STRING) { + printf("str: %s\n", str); + const char* value = at->text_value; + size_t len = strlen(value); + char* copy = (char*)malloc(len); + strncpy(copy, value, len); + printf("copy: %s\n", copy); + return copy; + } + } + return NULL; +} + +char* start_oauth_server() { + oauth2_config* conf = oauth2_init(CLIQ_CLIENT_ID, CLIQ_CLIENT_SECRET); + conf->access_auth_code_transformer = json_access_code_transformer; + oauth2_set_redirect_uri(conf, CLIQ_REDIRECT_URI); + // TODO generate true state instead of LOL + char* redir_uri = NULL; + char* grant_token = malloc(255 * sizeof(char)); + if (saved_grant_token == NULL) { + redir_uri = oauth2_request_auth_code(conf, CLIQ_AUTH_ENDPOINT, CLIQ_SCOPE, "LOL", "online"); + + printf("Visit this url and hit authorize: %s\n", redir_uri); + printf("Now put the auth token here: "); + + scanf("%s", grant_token); + } else { + strcpy(grant_token, saved_grant_token); + } + + if (grant_token == NULL) { + printf("grant_token is null"); + return NULL; + } + + //Now test token based auth + char* access_token = NULL; + if (saved_access_token == NULL) { + access_token = oauth2_access_auth_code(conf, CLIQ_TOKEN_ENDPOINT, grant_token, CLIQ_SCOPE); + if (access_token == NULL) { + printf("access_token: %ld is null\n", (long)access_token); + return NULL; + } + } else { + access_token = malloc(255 * sizeof(char)); + strcpy(access_token, saved_access_token); + } + + oauth2_set_auth_code(conf, access_token); + printf("Access Token: %s\n", access_token); + /* free(access_token); */ + + /* printf("Enter your Facebook status: "); */ + /* char status[255]; */ + /* scanf("%s", status); */ + /* char status2[255]; */ + /* sprintf(status2, "message=%s", status); */ + + /* access_token = oauth2_request(conf, "https://graph.facebook.com/slugonamission/feed", status2); */ + + /* printf("%s\n", access_token); */ + + oauth2_cleanup(conf); + return access_token; +} +#endif diff --git a/qlic_response_handler.c b/qlic_response_handler.c @@ -1,12 +1,19 @@ #include <qlic_response_handler.h> #include <stdio.h> +#include <string.h> -int qlic_handle_read_chat(char* response, size_t response_size, size_t nmemb, void *userp) { +int qlic_handle_read_chat(char* response, size_t item_size, size_t nmemb, void *userp) { /* printf("helo: %s\n", response); */ + /* size_t bytes = item_size * nmemb; */ +/* #define QLIC_TEST_TEST "{\"text\": \"Hi\"}" */ +/* printf("Test: item_size %zu", item_size); */ +/* printf("Test: response %s", response); */ return 0; } -int qlic_handle_send_message(char* response, size_t response_size, size_t nmemb, void *userp) { +size_t qlic_handle_send_message(char* response, size_t item_size, size_t nmemb, void *userp) { + size_t bytes = item_size * nmemb; + printf("Chunk size: %zu\n", nmemb); printf("%s\n", response); - return 0; + return bytes; } diff --git a/qlic_response_handler.h b/qlic_response_handler.h @@ -4,6 +4,6 @@ #include <stddef.h> int qlic_handle_read_chat(char* response, size_t response_size, size_t nmemb, void *userp); -int qlic_handle_send_message(char* response, size_t response_size, size_t nmemb, void *userp); +size_t qlic_handle_send_message(char* response, size_t response_size, size_t nmemb, void *userp); #endif diff --git a/qlic_types.h b/qlic_types.h @@ -3,7 +3,7 @@ #include <stddef.h> -typedef int (*qlic_response_callback)(char*, size_t, size_t, void*); +typedef size_t (*qlic_response_callback)(char*, size_t, size_t, void*); typedef struct QlicString { char* string; diff --git a/state.json b/state.json @@ -0,0 +1,8 @@ +{ + "user_id": { + "grant_token": "", + "access_token": "", + "refresh_token": "", + "time_generated": "" + } +}