From fea924350b6ba50dc0cb0e5e133cbbd914137e61 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Tue, 6 Aug 2019 15:44:18 +0200 Subject: Added a proper subscriptions listing for the direct conversations closer --- .gitmodules | 3 + CMakeLists.txt | 5 +- close_direct_conversations/CMakeLists.txt | 6 ++ close_direct_conversations/main.c | 91 +++++++++++++++++++++++++++++++ close_im/CMakeLists.txt | 9 --- close_im/main.c | 78 -------------------------- common/CMakeLists.txt | 1 + common/subscriptions.c | 39 +++++++++++++ common/subscriptions.h | 28 ++++++++++ external/uthash | 1 + restapi/CMakeLists.txt | 1 + restapi/subscriptions.c | 63 +++++++++++++++++++++ restapi/subscriptions.h | 9 +++ 13 files changed, 246 insertions(+), 88 deletions(-) create mode 100644 .gitmodules create mode 100644 close_direct_conversations/CMakeLists.txt create mode 100644 close_direct_conversations/main.c delete mode 100644 close_im/CMakeLists.txt delete mode 100644 close_im/main.c create mode 100644 common/subscriptions.c create mode 100644 common/subscriptions.h create mode 160000 external/uthash create mode 100644 restapi/subscriptions.c create mode 100644 restapi/subscriptions.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e9ff57b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/uthash"] + path = external/uthash + url = https://github.com/troydhanson/uthash diff --git a/CMakeLists.txt b/CMakeLists.txt index c6b6b2a..f6d77ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,10 @@ ExternalProject_Add(cjson ) include_directories(${CMAKE_BINARY_DIR}/cjson/src) +### uthash library ##### +include_directories("${PROJECT_SOURCE_DIR}/external/uthash/src") + ### Project subdirectories ##### -add_subdirectory(close_im) +add_subdirectory(close_direct_conversations) add_subdirectory(common) add_subdirectory(restapi) diff --git a/close_direct_conversations/CMakeLists.txt b/close_direct_conversations/CMakeLists.txt new file mode 100644 index 0000000..7aba3e4 --- /dev/null +++ b/close_direct_conversations/CMakeLists.txt @@ -0,0 +1,6 @@ +file(GLOB_RECURSE SOURCES *.c) + +ADD_EXECUTABLE(rocket_close_direct_conversations ${SOURCES}) +target_link_libraries(rocket_close_direct_conversations common restapi) + +install(TARGETS rocket_close_direct_conversations DESTINATION bin) diff --git a/close_direct_conversations/main.c b/close_direct_conversations/main.c new file mode 100644 index 0000000..0938982 --- /dev/null +++ b/close_direct_conversations/main.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +#include "common/config.h" +#include "common/util.h" +#include "restapi/auth.h" +#include "restapi/im.h" +#include "restapi/subscriptions.h" + +void print_subscription(const struct subscription* sub) +{ + if (sub->type == SUBSCRIPTION_DIRECT) + printf("\t%s\n", sub->name); +} + +int main(void) +{ + if (config_load(CONFIG_PATH) != 0) { + return 1; + } + + const char* login = config_get_login(); + char* termlogin = NULL; + if (login == NULL) { + size_t len = 0; + printf("Login: "); + ssize_t read = getline(&termlogin, &len, stdin); + if (read > 1) termlogin[read-1] = 0; + login = termlogin; + } + + const char* password = config_get_password(); + char* termpassword = NULL; + if (password == NULL) { + struct termios oflags, nflags; + tcgetattr(fileno(stdin), &oflags); + nflags = oflags; + nflags.c_lflag &= ~ECHO; + nflags.c_lflag |= ECHONL; + + if (tcsetattr(fileno(stdin), TCSADRAIN, &nflags) != 0) { + perror("tcsetattr"); + return -1; + } + + size_t len = 0; + printf("Password: "); + size_t read = getline(&termpassword, &len, stdin); + if (read > 1) termpassword[read-1] = 0; + + if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) { + perror("tcsetattr"); + return -1; + } + password = termpassword; + } + + if (restapi_login(login, password) == 0) { + struct subscription* subscriptions = restapi_subscriptions_get(); + + printf("Active direct conversations :\n"); + common_subscriptions_const_walk(subscriptions, &print_subscription); + common_subscriptions_free(subscriptions); + + while(1) { + char* buff = NULL; + size_t len2; + printf("Direct conversation to close: "); + ssize_t entry = getline(&buff, &len2, stdin); + if (entry > 1) { + buff[entry-1] = 0; + } else { + free(buff); + break; + } + restapi_im_close(buff); + free(buff); + } + } else { + printf("Couldn't init rest api.\n"); + } + + restapi_logout(); + config_clean(); + free(termlogin); + free(termpassword); + + return 0; +} diff --git a/close_im/CMakeLists.txt b/close_im/CMakeLists.txt deleted file mode 100644 index aec4090..0000000 --- a/close_im/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -file(GLOB_RECURSE SOURCES *.c) - -ADD_EXECUTABLE(rocket_close_im ${SOURCES}) -target_link_libraries(rocket_close_im common restapi) -target_link_libraries(rocket_close_im config curl) -add_dependencies(rocket_close_im cjson-build) -target_link_libraries(rocket_close_im ${CMAKE_CURRENT_BINARY_DIR}/../cjson/src/cjson-build/libcjson.a) - -install(TARGETS rocket_close_im DESTINATION bin) diff --git a/close_im/main.c b/close_im/main.c deleted file mode 100644 index c54ab25..0000000 --- a/close_im/main.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "common/util.h" -#include -#include -#include -#include - -#include "common/config.h" -#include "restapi/auth.h" -#include "restapi/im.h" - -int main(void) -{ - if (config_load(CONFIG_PATH) != 0) { - return 1; - } - - const char* login = config_get_login(); - char* termlogin = NULL; - if (login == NULL) { - size_t len = 0; - printf("Login: "); - ssize_t read = getline(&termlogin, &len, stdin); - if (read > 1) termlogin[read-1] = 0; - login = termlogin; - } - - const char* password = config_get_password(); - char* termpassword = NULL; - if (password == NULL) { - struct termios oflags, nflags; - tcgetattr(fileno(stdin), &oflags); - nflags = oflags; - nflags.c_lflag &= ~ECHO; - nflags.c_lflag |= ECHONL; - - if (tcsetattr(fileno(stdin), TCSADRAIN, &nflags) != 0) { - perror("tcsetattr"); - return -1; - } - - size_t len = 0; - printf("Password: "); - size_t read = getline(&termpassword, &len, stdin); - if (read > 1) termpassword[read-1] = 0; - - if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) { - perror("tcsetattr"); - return -1; - } - password = termpassword; - } - - if (restapi_login(login, password) == 0) { - while(1) { - char* buff = NULL; - size_t len2; - printf("IM to close: "); - ssize_t entry = getline(&buff, &len2, stdin); - if (entry > 1) { - buff[entry-1] = 0; - } else { - free(buff); - break; - } - restapi_im_close(buff); - free(buff); - } - } else { - printf("Couldn't init rest api.\n"); - } - - restapi_logout(); - config_clean(); - free(termlogin); - free(termpassword); - - return 0; -} diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index aa5402a..876571b 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -2,3 +2,4 @@ file(GLOB_RECURSE SOURCES *.c) include_directories("${CMAKE_CURRENT_BINARY_DIR}") ADD_LIBRARY(common STATIC ${SOURCES}) +target_link_libraries(common config curl) diff --git a/common/subscriptions.c b/common/subscriptions.c new file mode 100644 index 0000000..d6d15aa --- /dev/null +++ b/common/subscriptions.c @@ -0,0 +1,39 @@ +#include "subscriptions.h" + +void common_subscription_add(struct subscription** subscriptions, const char* id, const char* name, enum subscription_type type) +{ + struct subscription * subscription = common_subscription_new(id, name, type); + HASH_ADD_KEYPTR(hh, *subscriptions, subscription->id, strlen(id), subscription); +} + +struct subscription* common_subscription_new(const char* id, const char* name, enum subscription_type type) +{ + struct subscription* subscription = malloc(sizeof(struct subscription)); + subscription->id = malloc(strlen(id) + 1); + strcpy(subscription->id, id); + subscription->name = malloc(strlen(name) + 1); + strcpy(subscription->name, name); + subscription->type = type; + return subscription; +} + +void common_subscriptions_free(struct subscription* subscriptions) +{ + struct subscription *sub, *tmp; + + HASH_ITER(hh, subscriptions, sub, tmp) { + HASH_DEL(subscriptions, sub); + free(sub->id); + free(sub->name); + free(sub); + } +} + +void common_subscriptions_const_walk(const struct subscription* subscriptions, void (*func)(const struct subscription*)) +{ + const struct subscription *sub, *tmp; + + HASH_ITER(hh, subscriptions, sub, tmp) { + func(sub); + } +} diff --git a/common/subscriptions.h b/common/subscriptions.h new file mode 100644 index 0000000..6c10a24 --- /dev/null +++ b/common/subscriptions.h @@ -0,0 +1,28 @@ +#ifndef COMMON_SUBSCRIPTIONS_H_ +#define COMMON_SUBSCRIPTIONS_H_ + +#include + +static const char *subscription_type_str[] = { + "channel", "direct", "private", +}; + +enum subscription_type { + SUBSCRIPTION_CHANNEL, + SUBSCRIPTION_DIRECT, + SUBSCRIPTION_PRIVATE, +}; + +struct subscription { + char* id; + char* name; + enum subscription_type type; + UT_hash_handle hh; +}; + +void common_subscription_add(struct subscription** subscriptions, const char* id, const char* name, enum subscription_type type); +struct subscription* common_subscription_new(const char* id, const char* name, enum subscription_type type); +void common_subscriptions_free(struct subscription* subscriptions); +void common_subscriptions_const_walk(const struct subscription* subscriptions, void (*func)(const struct subscription*)); + +#endif diff --git a/external/uthash b/external/uthash new file mode 160000 index 0000000..f19dde2 --- /dev/null +++ b/external/uthash @@ -0,0 +1 @@ +Subproject commit f19dde22d80a563948a263afe00947e6e42ed8f4 diff --git a/restapi/CMakeLists.txt b/restapi/CMakeLists.txt index 45a22c2..e1cad6a 100644 --- a/restapi/CMakeLists.txt +++ b/restapi/CMakeLists.txt @@ -3,3 +3,4 @@ file(GLOB_RECURSE SOURCES *.c) ADD_LIBRARY(restapi STATIC ${SOURCES}) add_dependencies(restapi cjson-build) target_link_libraries(restapi common) +target_link_libraries(restapi ${CMAKE_CURRENT_BINARY_DIR}/../cjson/src/cjson-build/libcjson.a) diff --git a/restapi/subscriptions.c b/restapi/subscriptions.c new file mode 100644 index 0000000..b52ea9a --- /dev/null +++ b/restapi/subscriptions.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +#include "common/http.h" +#include "subscriptions.h" + +struct subscription* // returns NULL if error or a uthash of subscriptions that needs to be freed by the caller +restapi_subscriptions_get(void) +{ + struct subscription* subscriptions = NULL; + + const char* buffer = http_get("/api/v1/subscriptions.get"); + + if (buffer == NULL) { + fprintf(stderr, "Error while subscriptions_get, http get didn't return any data.\n"); + return NULL; + } + + cJSON* json = cJSON_Parse(buffer); + if (json == NULL) { + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr != NULL) + fprintf(stderr, "Json parsing error before: %s\n", error_ptr); + fprintf(stderr, "Error while subscriptions_get, couldn't parse json output :\n%s\n", buffer); + goto get_json_cleanup; + } + + const cJSON* success = cJSON_GetObjectItemCaseSensitive(json, "success"); + if (cJSON_IsTrue(success)) { + cJSON* updates = cJSON_GetObjectItemCaseSensitive(json, "update"); + if (!cJSON_IsArray(updates)) { + fprintf(stderr, "Error while subscriptions_get, couldn't parse json output :\n%s\n", buffer); + goto get_json_cleanup; + } + const cJSON* update = NULL; + cJSON_ArrayForEach(update, updates) { + const cJSON* id = cJSON_GetObjectItemCaseSensitive(update, "_id"); + const cJSON* name = cJSON_GetObjectItemCaseSensitive(update, "name"); + const cJSON* type = cJSON_GetObjectItemCaseSensitive(update, "t"); + const cJSON* open = cJSON_GetObjectItemCaseSensitive(update, "open"); + enum subscription_type etype; + if (!cJSON_IsString(id) || id->valuestring == NULL || !cJSON_IsString(name) || name->valuestring == NULL || !cJSON_IsString(type) || type->valuestring == NULL || !cJSON_IsTrue(open)) + continue; + if (strcmp(type->valuestring, "c") == 0) + etype = SUBSCRIPTION_CHANNEL; + else if (strcmp(type->valuestring, "d") == 0) + etype = SUBSCRIPTION_DIRECT; + else if (strcmp(type->valuestring, "p") == 0) + etype = SUBSCRIPTION_PRIVATE; + else { + fprintf(stderr, "Bug found : Unknown subscription type %s\n%s\n", type->valuestring, buffer); + exit(999); + } + common_subscription_add(&subscriptions, id->valuestring, name->valuestring, etype); + } + } +get_json_cleanup: + cJSON_Delete(json); + return subscriptions; +} diff --git a/restapi/subscriptions.h b/restapi/subscriptions.h new file mode 100644 index 0000000..0347e15 --- /dev/null +++ b/restapi/subscriptions.h @@ -0,0 +1,9 @@ +#ifndef RESTAPI_SUBSCRIPTIONS_H_ +#define RESTAPI_SUBSCRIPTIONS_H_ + +#include "common/subscriptions.h" + +struct subscription* // returns NULL if error or a uthash of subscriptions that needs to be freed by the caller +restapi_subscriptions_get(void); + +#endif -- cgit v1.2.3