5 * @author Hengband Team
9 #include "core/asking-player.h"
10 #include "core/player-redraw-types.h"
11 #include "core/stuff-handler.h"
12 #include "core/turn-compensator.h"
13 #include "core/visuals-reseter.h"
14 #include "dungeon/dungeon.h"
15 #include "game-option/special-options.h"
16 #include "io-dump/character-dump.h"
18 #include "io/input-key-acceptor.h"
19 #include "player/player-class.h"
20 #include "player/player-personality.h"
21 #include "player/player-race.h"
22 #include "realm/realm-names-table.h"
23 #include "system/angband-version.h"
24 #include "system/floor-type-definition.h"
25 #include "system/system-variables.h"
26 #include "term/gameterm.h"
27 #include "term/screen-processor.h"
28 #include "util/angband-files.h"
29 #include "view/display-messages.h"
30 #include "world/world.h"
35 #define CURL_STATICLIB
37 #include <curl/curl.h>
39 concptr screen_dump = NULL;
42 * internet resource value
44 #define HTTP_TIMEOUT 30 /*!< デフォルトのタイムアウト時間(秒) / Timeout length (second) */
47 #define SCORE_PATH "http://mars.kmc.gr.jp/~dis/heng_score/register_score.php" /*!< スコア開示URL */
49 #define SCORE_PATH "http://moon.kmc.gr.jp/hengband/hengscore-en/score.cgi" /*!< スコア開示URL */
53 * simple buffer library
62 #define BUFSIZE (65536) /*!< スコアサーバ転送バッファサイズ */
66 * @return 確保したバッファの参照ポインタ
68 static BUF *buf_new(void)
71 p = static_cast<BUF*>(malloc(sizeof(BUF)));
76 p->max_size = BUFSIZE;
77 p->data = static_cast<char*>(malloc(BUFSIZE));
88 * @param b 解放するバッファの参照ポインタ
90 static void buf_delete(BUF *b)
97 * @brief 転送用バッファにデータを追加する
98 * @param buf 追加先バッファの参照ポインタ
103 static int buf_append(BUF *buf, concptr data, size_t size)
105 while (buf->size + size > buf->max_size) {
107 if ((tmp = static_cast<char*>(malloc(buf->max_size * 2))) == NULL)
110 memcpy(tmp, buf->data, buf->max_size);
117 memcpy(buf->data + buf->size, data, size);
124 * @brief 転送用バッファにフォーマット指定した文字列データを追加する
125 * @param buf 追加先バッファの参照ポインタ
126 * @param fmt 文字列フォーマット
129 static int buf_sprintf(BUF *buf, concptr fmt, ...)
136 #if defined(HAVE_VSNPRINTF)
137 ret = vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
139 ret = vsprintf(tmpbuf, fmt, ap);
146 ret = buf_append(buf, tmpbuf, strlen(tmpbuf));
150 size_t read_callback(char *buffer, size_t size, size_t nitems, void *userdata)
152 BUF *buf = static_cast<BUF*>(userdata);
153 const size_t remain = buf->size - buf->read_head;
154 const size_t copy_size = MIN(size * nitems, remain);
156 strncpy(buffer, buf->data + buf->read_head, copy_size);
157 buf->read_head += copy_size;
163 * @brief HTTPによるダンプ内容伝送
165 * @param buf 伝送内容バッファ
166 * @return 送信に成功した場合TRUE、失敗した場合FALSE
168 static bool http_post(concptr url, BUF *buf)
170 bool succeeded = FALSE;
171 CURL *curl = curl_easy_init();
176 struct curl_slist *slist = NULL;
177 slist = curl_slist_append(slist,
180 "Content-Type: text/plain; charset=SHIFT_JIS"
183 "Content-Type: text/plain; charset=EUC-JP"
186 "Content-Type: text/plain; charset=ASCII"
190 curl_easy_setopt(curl, CURLOPT_URL, url);
191 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
194 snprintf(user_agent, sizeof(user_agent), "Hengband %d.%d.%d", FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
195 curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent);
197 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
198 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
200 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
201 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, HTTP_TIMEOUT);
202 curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_TIMEOUT);
204 curl_easy_setopt(curl, CURLOPT_POST, 1);
206 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
207 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10);
208 curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
211 curl_easy_setopt(curl, CURLOPT_READDATA, buf);
212 curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
213 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, buf->size);
215 if (curl_easy_perform(curl) == CURLE_OK) {
217 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
218 if (response_code == 200) {
223 curl_slist_free_all(slist);
224 curl_easy_cleanup(curl);
230 * @brief キャラクタダンプを作って BUFに保存
231 * @param creature_ptr プレーヤーへの参照ポインタ
232 * @param dumpbuf 伝送内容バッファ
235 static errr make_dump(player_type *creature_ptr, BUF *dumpbuf, void (*update_playtime)(void), display_player_pf display_player)
239 GAME_TEXT file_name[1024];
241 /* Open a new file */
242 fff = angband_fopen_temp(file_name, 1024);
245 msg_format("一時ファイル %s を作成できませんでした。", file_name);
247 msg_format("Failed to create temporary file %s.", file_name);
253 /* 一旦一時ファイルを作る。通常のダンプ出力と共通化するため。 */
254 make_character_dump(creature_ptr, fff, update_playtime, display_player);
258 fff = angband_fopen(file_name, "r");
260 while (fgets(buf, 1024, fff)) {
261 (void)buf_sprintf(dumpbuf, "%s", buf);
271 * @brief スクリーンダンプを作成する/ Make screen dump to buffer
272 * @return 作成したスクリーンダンプの参照ポインタ
274 concptr make_screen_dump(player_type *creature_ptr, void (*process_autopick_file_command)(char *))
276 static concptr html_head[] = {
277 "<html>\n<body text=\"#ffffff\" bgcolor=\"#000000\">\n",
281 static concptr html_foot[] = {
283 "</body>\n</html>\n",
288 term_get_size(&wid, &hgt);
292 screen_buf = buf_new();
293 if (screen_buf == NULL)
296 bool old_use_graphics = use_graphics;
297 if (old_use_graphics) {
298 /* Clear -more- prompt first */
301 use_graphics = FALSE;
302 reset_visuals(creature_ptr, process_autopick_file_command);
304 creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
305 handle_stuff(creature_ptr);
308 for (int i = 0; html_head[i]; i++)
309 buf_sprintf(screen_buf, html_head[i]);
311 /* Dump the screen */
312 for (int y = 0; y < hgt; y++) {
315 buf_sprintf(screen_buf, "\n");
318 TERM_COLOR a = 0, old_a = 0;
320 for (int x = 0; x < wid - 1; x++) {
323 /* Get the attr/char */
324 (void)(term_what(x, y, &a, &c));
347 c = (a == 0x09) ? '%' : '#';
353 if ((y == 0 && x == 0) || a != old_a) {
354 rv = angband_color_table[a][1];
355 gv = angband_color_table[a][2];
356 bv = angband_color_table[a][3];
357 buf_sprintf(screen_buf, "%s<font color=\"#%02x%02x%02x\">", ((y == 0 && x == 0) ? "" : "</font>"), rv, gv, bv);
362 buf_sprintf(screen_buf, "%s", cc);
364 buf_sprintf(screen_buf, "%c", c);
368 buf_sprintf(screen_buf, "</font>");
370 for (int i = 0; html_foot[i]; i++)
371 buf_sprintf(screen_buf, html_foot[i]);
373 /* Screen dump size is too big ? */
375 if (screen_buf->size + 1 > SCREEN_BUF_MAX_SIZE) {
378 /* Terminate string */
379 buf_append(screen_buf, "", 1);
381 ret = string_make(screen_buf->data);
385 buf_delete(screen_buf);
387 if (!old_use_graphics)
391 reset_visuals(creature_ptr, process_autopick_file_command);
393 creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
394 handle_stuff(creature_ptr);
399 * todo メッセージは言語選択の関数マクロで何とかならんか?
400 * @brief スコア転送処理のメインルーチン
401 * @param creature_ptr プレーヤーへの参照ポインタ
402 * @return 正常終了の時0、異常があったら1
404 errr report_score(player_type *creature_ptr, void (*update_playtime)(void), display_player_pf display_player)
409 char seikakutmp[128];
413 sprintf(seikakutmp, "%s%s", ap_ptr->title, (ap_ptr->no ? "の" : ""));
415 sprintf(seikakutmp, "%s ", ap_ptr->title);
418 buf_sprintf(score, "name: %s\n", creature_ptr->name);
419 buf_sprintf(score, "version: %s\n", title);
420 buf_sprintf(score, "score: %d\n", calc_score(creature_ptr));
421 buf_sprintf(score, "level: %d\n", creature_ptr->lev);
422 buf_sprintf(score, "depth: %d\n", creature_ptr->current_floor_ptr->dun_level);
423 buf_sprintf(score, "maxlv: %d\n", creature_ptr->max_plv);
424 buf_sprintf(score, "maxdp: %d\n", max_dlv[DUNGEON_ANGBAND]);
425 buf_sprintf(score, "au: %d\n", creature_ptr->au);
426 buf_sprintf(score, "turns: %d\n", turn_real(creature_ptr, current_world_ptr->game_turn));
427 buf_sprintf(score, "sex: %d\n", creature_ptr->psex);
428 buf_sprintf(score, "race: %s\n", rp_ptr->title);
429 buf_sprintf(score, "class: %s\n", cp_ptr->title);
430 buf_sprintf(score, "seikaku: %s\n", seikakutmp);
431 buf_sprintf(score, "realm1: %s\n", realm_names[creature_ptr->realm1]);
432 buf_sprintf(score, "realm2: %s\n", realm_names[creature_ptr->realm2]);
433 buf_sprintf(score, "killer: %s\n", creature_ptr->died_from);
434 buf_sprintf(score, "-----charcter dump-----\n");
436 make_dump(creature_ptr, score, update_playtime, display_player);
439 buf_sprintf(score, "-----screen shot-----\n");
440 buf_append(score, screen_dump, strlen(screen_dump));
445 bool succeeded = FALSE;
449 prt(_("スコア送信中...", "Sending the score..."), 0, 0);
452 if (http_post(SCORE_PATH, score)) {
455 prt(_("スコア・サーバへの送信に失敗しました。", "Failed to send to the score server."), 0, 0);
458 if (!get_check_strict(creature_ptr, _("もう一度接続を試みますか? ", "Try again? "), CHECK_NO_HISTORY)) {
466 return succeeded ? 0 : 1;
469 concptr screen_dump = NULL;
470 #endif /* WORLD_SCORE */