From 84991646c03b79c9983cc288420c255679035b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AB=8F=E8=A8=AA=E5=AD=90?= Date: Sat, 19 Aug 2023 03:02:05 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92?= =?UTF-8?q?=E5=88=86=E3=81=91=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 4 +- api.c | 37 ++++++++ api.h | 16 ++++ commands.c | 22 +++++ commands.h | 15 ++++ main.c | 243 ++-------------------------------------------------- meinfo.c | 39 +++++++++ meinfo.h | 6 ++ rooms.c | 128 +++++++++++++++++++++++++++ rooms.h | 7 ++ roomsinfo.c | 44 ++++++++++ roomsinfo.h | 6 ++ 12 files changed, 328 insertions(+), 239 deletions(-) create mode 100644 api.c create mode 100644 api.h create mode 100644 commands.c create mode 100644 commands.h create mode 100644 meinfo.c create mode 100644 meinfo.h create mode 100644 rooms.c create mode 100644 rooms.h create mode 100644 roomsinfo.c create mode 100644 roomsinfo.h diff --git a/Makefile b/Makefile index 3b231be..c685174 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,8 @@ LDFLAGS = -shared -lcurl -lcjson all: $(TARGET) -$(TARGET): main.c - $(CC) $(DEBUG) $(CFLAGS) $(LDFLAGS) -o $@ $< +$(TARGET): commands.c api.c meinfo.c roomsinfo.c rooms.c main.c + $(CC) $(DEBUG) $(CFLAGS) $(LDFLAGS) -o $@ $^ install: install -d $(LIBDIR) diff --git a/api.c b/api.c new file mode 100644 index 0000000..6af53aa --- /dev/null +++ b/api.c @@ -0,0 +1,37 @@ +#include + +#include +#include + +#include "commands.h" +#include "api.h" + +ApiResponse makeApiRequest (const ApiRequest *request) { + ApiResponse response = {0}; + + CURL *curl = curl_easy_init(); + if (!curl) { + return response; + } + + Buffer readBuffer = { NULL, 0 }; + struct curl_slist *headers = NULL; + char header[256]; + snprintf(header, sizeof(header), "X-ChatWorkToken: %s", request->token); + headers = curl_slist_append(headers, header); + + curl_easy_setopt(curl, CURLOPT_URL, request->url); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); + + response.result = curl_easy_perform(curl); + response.data = cJSON_Parse(readBuffer.data); + free(readBuffer.data); + + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + + return response; +} diff --git a/api.h b/api.h new file mode 100644 index 0000000..cf14a3a --- /dev/null +++ b/api.h @@ -0,0 +1,16 @@ +#ifndef _API_H_ +#define _API_H_ + +typedef struct { + const char *url; + const char *token; +} ApiRequest; + +typedef struct { + CURLcode result; + cJSON *data; +} ApiResponse; + +ApiResponse makeApiRequest (const ApiRequest *request); + +#endif diff --git a/commands.c b/commands.c new file mode 100644 index 0000000..856f8c2 --- /dev/null +++ b/commands.c @@ -0,0 +1,22 @@ +#include +#include + +#include + +#include "commands.h" + +struct t_config_file *chatwork_config_file = NULL; +struct t_config_option *chatwork_config_token = NULL; +struct t_weechat_plugin *weechat_plugin = NULL; + +size_t WriteCallback (void* contents, size_t size, size_t nmemb, void* userp) { + size_t totalSize = size * nmemb; + Buffer *buffer = (Buffer *)userp; + char *temp = realloc(buffer->data, buffer->size + totalSize + 1); + if (temp == NULL) return 0; + buffer->data = temp; + memcpy(buffer->data + buffer->size, contents, totalSize); + buffer->size += totalSize; + buffer->data[buffer->size] = '\0'; + return totalSize; +} diff --git a/commands.h b/commands.h new file mode 100644 index 0000000..5fd1d38 --- /dev/null +++ b/commands.h @@ -0,0 +1,15 @@ +#ifndef _COMMANDS_H_ +#define _COMMANDS_H_ + +extern struct t_config_file *chatwork_config_file; +extern struct t_config_option *chatwork_config_token; +extern struct t_weechat_plugin *weechat_plugin; + +typedef struct { + char *data; + size_t size; +} Buffer; + +size_t WriteCallback (void* contents, size_t size, size_t nmemb, void* userp); + +#endif diff --git a/main.c b/main.c index 57ec82d..2211e9e 100644 --- a/main.c +++ b/main.c @@ -6,250 +6,19 @@ #include #include +#include "commands.h" +#include "api.h" +#include "meinfo.h" +#include "roomsinfo.h" +#include "rooms.h" + WEECHAT_PLUGIN_NAME("chatwork"); WEECHAT_PLUGIN_DESCRIPTION("Chatwork対応"); WEECHAT_PLUGIN_AUTHOR("洩矢諏訪子 "); WEECHAT_PLUGIN_VERSION("0.1"); WEECHAT_PLUGIN_LICENSE("GPL3"); -struct t_config_file *chatwork_config_file = NULL; -struct t_config_option *chatwork_config_token = NULL; -struct t_weechat_plugin *weechat_plugin = NULL; - -typedef struct { - const char *url; - const char *token; -} ApiRequest; - -typedef struct { - CURLcode result; - cJSON *data; -} ApiResponse; - -typedef struct { - char *data; - size_t size; -} Buffer; - -size_t WriteCallback (void* contents, size_t size, size_t nmemb, void* userp) { - size_t totalSize = size * nmemb; - Buffer *buffer = (Buffer *)userp; - char *temp = realloc(buffer->data, buffer->size + totalSize + 1); - if (temp == NULL) return 0; - buffer->data = temp; - memcpy(buffer->data + buffer->size, contents, totalSize); - buffer->size += totalSize; - buffer->data[buffer->size] = '\0'; - return totalSize; -} - -ApiResponse makeApiRequest (const ApiRequest *request) { - ApiResponse response = {0}; - - CURL *curl = curl_easy_init(); - if (!curl) { - return response; - } - - Buffer readBuffer = { NULL, 0 }; - struct curl_slist *headers = NULL; - char header[256]; - snprintf(header, sizeof(header), "X-ChatWorkToken: %s", request->token); - headers = curl_slist_append(headers, header); - - curl_easy_setopt(curl, CURLOPT_URL, request->url); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - - response.result = curl_easy_perform(curl); - response.data = cJSON_Parse(readBuffer.data); - free(readBuffer.data); - - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - - return response; -} - -void getMeInfo (struct t_gui_buffer *buffer, const char *token) { - ApiRequest request = { - .url = "https://api.chatwork.com/v2/me", - .token = token, - }; - ApiResponse response = makeApiRequest(&request); - - if (response.result != CURLE_OK) { - weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(response.result)); - } else { - cJSON *root = response.data; - if (root != NULL) { - const char *name = cJSON_GetObjectItem(root, "name")->valuestring; - weechat_printf(buffer, "GETリクエストに成功:%s\n", name); - } else { - weechat_printf(buffer, "JSONパーシングエラー。\n"); - } - - cJSON_Delete(root); - } -} - -void getRoomsInfo (struct t_gui_buffer *buffer, const char *token) { - ApiRequest request = { - .url = "https://api.chatwork.com/v2/rooms", - .token = token, - }; - ApiResponse response = makeApiRequest(&request); - - if (response.result != CURLE_OK) { - weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(response.result)); - } else { - cJSON *root = response.data; - if (root != NULL) { - int size = cJSON_GetArraySize(root); - - for (int i = 0; i < size; i++) { - cJSON *room = cJSON_GetArrayItem(root, i); - int room_id = cJSON_GetObjectItem(room, "room_id")->valueint; - const char *name = cJSON_GetObjectItem(room, "name")->valuestring; - const char *type = cJSON_GetObjectItem(room, "type")->valuestring; - if (strcmp(type, "my") == 0) { - weechat_printf(buffer, "%d - %s\n", room_id, name); - } else if (strcmp(type, "direct") == 0) { - weechat_printf(buffer, "%d - DM %s\n", room_id, name); - } else if (strcmp(type, "group") == 0) { - weechat_printf(buffer, "%d - グループ %s\n", room_id, name); - } - } - } else { - weechat_printf(buffer, "JSONパーシングエラー。\n"); - } - - cJSON_Delete(root); - } -} - -void populateUserList (struct t_gui_buffer *buffer, const char *token, int room_id) { - char url[256]; - snprintf(url, sizeof(url), "https://api.chatwork.com/v2/rooms/%d/members", room_id); - - ApiRequest req = { - .url = url, - .token = token, - }; - ApiResponse res = makeApiRequest(&req); - - if (res.result != CURLE_OK) { - weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(res.result)); - return; - } - - cJSON *members = res.data; - if (members != NULL) { - weechat_nicklist_remove_all(buffer); - - for (int i = 0; i < cJSON_GetArraySize(members); i++) { - cJSON *member = cJSON_GetArrayItem(members, i); - const char *name = cJSON_GetObjectItem(member, "name")->valuestring; - const char *role = cJSON_GetObjectItem(member, "role")->valuestring; - char *rolepref = NULL; - char *rolecol = NULL; - if (strcmp(role, "admin") == 0) { - rolepref = "@"; - rolecol = "weechat.color.*214"; - } - weechat_nicklist_add_nick(buffer, NULL, name, "weechat.color.nicklist_nick", rolepref, rolecol, 1); - } - cJSON_Delete(members); - } else { - weechat_printf(buffer, "JSONパーシングエラー。\n"); - } -} - -void getRoom (struct t_gui_buffer *buffer, const char *token, int room_id) { - char url1[256]; - char url2[256]; - snprintf(url1, sizeof(url1), "https://api.chatwork.com/v2/rooms/%d", room_id); - snprintf(url2, sizeof(url2), "https://api.chatwork.com/v2/rooms/%d/messages?force=1", room_id); - - ApiRequest req = { - .url = url1, - .token = token, - }; - ApiResponse res = makeApiRequest(&req); - - if (res.result != CURLE_OK) { - weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(res.result)); - } else { - cJSON *bufroot = res.data; - if (bufroot != NULL) { - const char *bufname = cJSON_GetObjectItem(bufroot, "name")->valuestring; - struct t_gui_buffer *buf = weechat_buffer_new(bufname, NULL, NULL, NULL, NULL, NULL, NULL); - cJSON_Delete(bufroot); - - populateUserList(buf, token, room_id); - weechat_buffer_set(buf, "display", "1"); - weechat_buffer_set(buf, "nicklist", "1"); - - ApiRequest request = { - .url = url2, - .token = token, - }; - ApiResponse response = makeApiRequest(&request); - - if (response.result != CURLE_OK) { - weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(response.result)); - } else { - cJSON *root = response.data; - if (root != NULL) { - for (int i = 0; i < cJSON_GetArraySize(root); i++) { - cJSON *message = cJSON_GetArrayItem(root, i); - cJSON *account = cJSON_GetObjectItem(message, "account"); - const char *name = cJSON_GetObjectItem(account, "name")->valuestring; - const char *body = cJSON_GetObjectItem(message, "body")->valuestring; - int send_time = cJSON_GetObjectItem(message, "send_time")->valueint; - - // send_timeはUnixから日時に - char timestamp[64]; - time_t raw_time = send_time; - struct tm *timeinfo = localtime(&raw_time); - strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", timeinfo); - - char fbody[4096]; - - // TODO: 返事 - //if (sscanf(body, "[To:%d]", &account_id) == 1) { - // weechat_printf(buffer, "%sさんに返事:\n", user); - //} else { - - // ファイル共有 - if (strstr(body, "[download:") != NULL) { - char download_id[64]; - sscanf(body, "[info][title][dtext:file_uploaded][/title][download:%63[^]]]", download_id); - snprintf(fbody, sizeof(fbody), "%s | [ファイル] https://www.chatwork.com/gateway/download_file.php?bin=1&file_id=%s&preview=0", name, download_id); - } else { - snprintf(fbody, sizeof(fbody), "%s | %s", name, body); - } - - // TODO: nickはメッセージの前に表示する - weechat_printf_date_tags(buf, raw_time, NULL, "%s\n", fbody); - //} // TODO: 返事 - } - } else { - weechat_printf(buffer, "JSONパーシングエラー。\n"); - } - - cJSON_Delete(root); - } - } else { - weechat_printf(buffer, "JSONパーシングエラー。\n"); - } - } -} - int chatwork_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - weechat_printf(buffer, "Chatworkコマンドを実行しました。\n"); const char *token = weechat_config_string(chatwork_config_token); if (!token || strlen(token) == 0) { weechat_printf(buffer, "トークンを見つけられませんでした。\n"); diff --git a/meinfo.c b/meinfo.c new file mode 100644 index 0000000..4f870dc --- /dev/null +++ b/meinfo.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#include "commands.h" +#include "api.h" +#include "meinfo.h" + +void getMeInfo (struct t_gui_buffer *buffer, const char *token) { + ApiRequest request = { + .url = "https://api.chatwork.com/v2/me", + .token = token, + }; + ApiResponse response = makeApiRequest(&request); + + if (response.result != CURLE_OK) { + weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(response.result)); + } else { + cJSON *root = response.data; + if (root != NULL) { + int account_id = cJSON_GetObjectItem(root, "account_id")->valueint; + const char *name = cJSON_GetObjectItem(root, "name")->valuestring; + const char *chatwork_id = cJSON_GetObjectItem(root, "chatwork_id")->valuestring; + int organization_id = cJSON_GetObjectItem(root, "organization_id")->valueint; + const char *organization_name = cJSON_GetObjectItem(root, "organization_name")->valuestring; + const char *department = cJSON_GetObjectItem(root, "department")->valuestring; + weechat_printf(buffer, "アカウントID:%d\n", account_id); + weechat_printf(buffer, "名前:%s\n", name); + weechat_printf(buffer, "チャットワークID:%s\n", chatwork_id); + weechat_printf(buffer, "組織ID:%d\n", organization_id); + weechat_printf(buffer, "組織名:%s\n", organization_name); + weechat_printf(buffer, "部局:%s\n", department); + } else { + weechat_printf(buffer, "JSONパーシングエラー。\n"); + } + + cJSON_Delete(root); + } +} diff --git a/meinfo.h b/meinfo.h new file mode 100644 index 0000000..b6fbd46 --- /dev/null +++ b/meinfo.h @@ -0,0 +1,6 @@ +#ifndef _MEINFO_H_ +#define _MEINFO_H_ + +void getMeInfo (struct t_gui_buffer *buffer, const char *token); + +#endif diff --git a/rooms.c b/rooms.c new file mode 100644 index 0000000..f4e1b0c --- /dev/null +++ b/rooms.c @@ -0,0 +1,128 @@ +#include +#include + +#include +#include +#include + +#include "commands.h" +#include "api.h" +#include "rooms.h" + +void populateUserList (struct t_gui_buffer *buffer, const char *token, int room_id) { + char url[256]; + snprintf(url, sizeof(url), "https://api.chatwork.com/v2/rooms/%d/members", room_id); + + ApiRequest req = { + .url = url, + .token = token, + }; + ApiResponse res = makeApiRequest(&req); + + if (res.result != CURLE_OK) { + weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(res.result)); + return; + } + + cJSON *members = res.data; + if (members != NULL) { + weechat_nicklist_remove_all(buffer); + + for (int i = 0; i < cJSON_GetArraySize(members); i++) { + cJSON *member = cJSON_GetArrayItem(members, i); + const char *name = cJSON_GetObjectItem(member, "name")->valuestring; + const char *role = cJSON_GetObjectItem(member, "role")->valuestring; + char *rolepref = NULL; + char *rolecol = NULL; + if (strcmp(role, "admin") == 0) { + rolepref = "@"; + rolecol = "weechat.color.*214"; + } + weechat_nicklist_add_nick(buffer, NULL, name, "weechat.color.nicklist_nick", rolepref, rolecol, 1); + } + cJSON_Delete(members); + } else { + weechat_printf(buffer, "JSONパーシングエラー。\n"); + } +} + +void getRoom (struct t_gui_buffer *buffer, const char *token, int room_id) { + char url1[256]; + char url2[256]; + snprintf(url1, sizeof(url1), "https://api.chatwork.com/v2/rooms/%d", room_id); + snprintf(url2, sizeof(url2), "https://api.chatwork.com/v2/rooms/%d/messages?force=1", room_id); + + ApiRequest req = { + .url = url1, + .token = token, + }; + ApiResponse res = makeApiRequest(&req); + + if (res.result != CURLE_OK) { + weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(res.result)); + } else { + cJSON *bufroot = res.data; + if (bufroot != NULL) { + const char *bufname = cJSON_GetObjectItem(bufroot, "name")->valuestring; + struct t_gui_buffer *buf = weechat_buffer_new(bufname, NULL, NULL, NULL, NULL, NULL, NULL); + cJSON_Delete(bufroot); + + populateUserList(buf, token, room_id); + weechat_buffer_set(buf, "display", "1"); + weechat_buffer_set(buf, "nicklist", "1"); + + ApiRequest request = { + .url = url2, + .token = token, + }; + ApiResponse response = makeApiRequest(&request); + + if (response.result != CURLE_OK) { + weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(response.result)); + } else { + cJSON *root = response.data; + if (root != NULL) { + for (int i = 0; i < cJSON_GetArraySize(root); i++) { + cJSON *message = cJSON_GetArrayItem(root, i); + cJSON *account = cJSON_GetObjectItem(message, "account"); + const char *name = cJSON_GetObjectItem(account, "name")->valuestring; + const char *body = cJSON_GetObjectItem(message, "body")->valuestring; + int send_time = cJSON_GetObjectItem(message, "send_time")->valueint; + + // send_timeはUnixから日時に + char timestamp[64]; + time_t raw_time = send_time; + struct tm *timeinfo = localtime(&raw_time); + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", timeinfo); + + char fbody[4096]; + + // TODO: 返事 + //if (sscanf(body, "[To:%d]", &account_id) == 1) { + // weechat_printf(buffer, "%sさんに返事:\n", user); + //} else { + + // ファイル共有 + if (strstr(body, "[download:") != NULL) { + char download_id[64]; + sscanf(body, "[info][title][dtext:file_uploaded][/title][download:%63[^]]]", download_id); + snprintf(fbody, sizeof(fbody), "%s | [ファイル] https://www.chatwork.com/gateway/download_file.php?bin=1&file_id=%s&preview=0", name, download_id); + } else { + snprintf(fbody, sizeof(fbody), "%s | %s", name, body); + } + + // TODO: nickはメッセージの前に表示する + weechat_printf_date_tags(buf, raw_time, NULL, "%s\n", fbody); + //} // TODO: 返事 + } + } else { + weechat_printf(buffer, "JSONパーシングエラー。\n"); + } + + cJSON_Delete(root); + } + } else { + weechat_printf(buffer, "JSONパーシングエラー。\n"); + } + } +} diff --git a/rooms.h b/rooms.h new file mode 100644 index 0000000..bbe8135 --- /dev/null +++ b/rooms.h @@ -0,0 +1,7 @@ +#ifndef _ROOMS_H_ +#define _ROOMS_H_ + +void populateUserList (struct t_gui_buffer *buffer, const char *token, int room_id); +void getRoom (struct t_gui_buffer *buffer, const char *token, int room_id); + +#endif diff --git a/roomsinfo.c b/roomsinfo.c new file mode 100644 index 0000000..3b84de5 --- /dev/null +++ b/roomsinfo.c @@ -0,0 +1,44 @@ +#include + +#include +#include +#include + +#include "commands.h" +#include "api.h" +#include "roomsinfo.h" + +void getRoomsInfo (struct t_gui_buffer *buffer, const char *token) { + ApiRequest request = { + .url = "https://api.chatwork.com/v2/rooms", + .token = token, + }; + ApiResponse response = makeApiRequest(&request); + + if (response.result != CURLE_OK) { + weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(response.result)); + } else { + cJSON *root = response.data; + if (root != NULL) { + int size = cJSON_GetArraySize(root); + + for (int i = 0; i < size; i++) { + cJSON *room = cJSON_GetArrayItem(root, i); + int room_id = cJSON_GetObjectItem(room, "room_id")->valueint; + const char *name = cJSON_GetObjectItem(room, "name")->valuestring; + const char *type = cJSON_GetObjectItem(room, "type")->valuestring; + if (strcmp(type, "my") == 0) { + weechat_printf(buffer, "%d - %s\n", room_id, name); + } else if (strcmp(type, "direct") == 0) { + weechat_printf(buffer, "%d - DM %s\n", room_id, name); + } else if (strcmp(type, "group") == 0) { + weechat_printf(buffer, "%d - グループ %s\n", room_id, name); + } + } + } else { + weechat_printf(buffer, "JSONパーシングエラー。\n"); + } + + cJSON_Delete(root); + } +} diff --git a/roomsinfo.h b/roomsinfo.h new file mode 100644 index 0000000..ff45acb --- /dev/null +++ b/roomsinfo.h @@ -0,0 +1,6 @@ +#ifndef _ROOMSINFO_H_ +#define _ROOMSINFO_H_ + +void getRoomsInfo (struct t_gui_buffer *buffer, const char *token); + +#endif