diff --git a/main.c b/main.c index e74e427..57ec82d 100644 --- a/main.c +++ b/main.c @@ -1,8 +1,10 @@ +#include +#include +#include + #include #include #include -#include -#include WEECHAT_PLUGIN_NAME("chatwork"); WEECHAT_PLUGIN_DESCRIPTION("Chatwork対応"); @@ -21,24 +23,231 @@ typedef struct { typedef struct { CURLcode result; - char *data; + cJSON *data; } ApiResponse; -ApiResponse makeApiRequest (const ApiRequest *request) { - // TODO -} +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; - char** buffer_ptr = (char**)userp; - char* temp = realloc(*buffer_ptr, strlen(*buffer_ptr) + totalSize + 1); + Buffer *buffer = (Buffer *)userp; + char *temp = realloc(buffer->data, buffer->size + totalSize + 1); if (temp == NULL) return 0; - *buffer_ptr = temp; - memcpy(*buffer_ptr + strlen(*buffer_ptr), contents, totalSize); - (*buffer_ptr)[strlen(*buffer_ptr) + totalSize] = '\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); @@ -47,43 +256,35 @@ int chatwork_command_cb (const void *pointer, void *data, struct t_gui_buffer *b return WEECHAT_RC_ERROR; } - CURL *curl = curl_easy_init(); - if (!curl) { - weechat_printf(buffer, "libcurlを起動出来なかった。\n"); - return WEECHAT_RC_ERROR; + if (argc < 2 || (argc == 2 && strcmp(argv[1], "help") == 0)) { + weechat_printf(buffer, "使い方: /chatwork me - ユーザー情報を表示\n"); + weechat_printf(buffer, " /chatwork rooms - 部屋を表示\n"); + weechat_printf(buffer, " /chatwork join 部屋番号 - 部屋に参加\n"); + weechat_printf(buffer, " /chatwork upload パス - ファイルをアップロードする\n"); + return WEECHAT_RC_OK; } - char *readBuffer = calloc(1, 1); - curl_easy_setopt(curl, CURLOPT_URL, "https://api.chatwork.com/v2/me"); - - struct curl_slist *headers = NULL; - char header[256]; - snprintf(header, sizeof(header), "X-ChatWorkToken: %s", token); - headers = curl_slist_append(headers, header); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - - CURLcode res = curl_easy_perform(curl); - if (res != CURLE_OK) { - weechat_printf(buffer, "GETリクエストエラー:%s\n", curl_easy_strerror(res)); - } else { - cJSON *root = cJSON_Parse(readBuffer); - if (root != NULL) { - const char *name = cJSON_GetObjectItem(root, "name")->valuestring; - weechat_printf(buffer, "GETリクエストに成功:%s\n", name); - cJSON_Delete(root); + if (strcmp(argv[1], "me") == 0) { + getMeInfo(buffer, token); + } else if (strcmp(argv[1], "rooms") == 0) { + getRoomsInfo(buffer, token); + } else if (strcmp(argv[1], "join") == 0) { + if (argc == 3) { + getRoom(buffer, token, atoi(argv[2])); } else { - weechat_printf(buffer, "JSONパーシングエラー。\n"); + weechat_printf(buffer, "部屋番号をご入力下さい。\n"); } + } else if (strcmp(argv[1], "upload") == 0) { + if (argc == 3) { + getRoom(buffer, token, atoi(argv[2])); + } else { + weechat_printf(buffer, "パスをご入力下さい。\n"); + } + } else { + weechat_printf(buffer, "不明なコマンド:%s\n", argv[1]); + weechat_printf(buffer, "すべてのコマンドを表示するには、/chatwork helpを実行して下さい。\n"); } - // 掃除 - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - free(readBuffer); - return WEECHAT_RC_OK; }