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 "mind/mind-elementalist.h"
20 #include "player/player-class.h"
21 #include "player/player-personality.h"
22 #include "player/player-race.h"
23 #include "realm/realm-names-table.h"
24 #include "system/angband-version.h"
25 #include "system/floor-type-definition.h"
26 #include "system/system-variables.h"
27 #include "term/gameterm.h"
28 #include "term/screen-processor.h"
29 #include "util/angband-files.h"
30 #include "view/display-messages.h"
31 #include "world/world.h"
36 #define CURL_STATICLIB
38 #include <curl/curl.h>
40 concptr screen_dump = NULL;
43 * internet resource value
45 #define HTTP_TIMEOUT 30 /*!< デフォルトのタイムアウト時間(秒) / Timeout length (second) */
48 #define SCORE_PATH "http://mars.kmc.gr.jp/~dis/heng_score/register_score.php" /*!< スコア開示URL */
50 #define SCORE_PATH "http://moon.kmc.gr.jp/hengband/hengscore-en/score.cgi" /*!< スコア開示URL */
54 * simple buffer library
63 #define BUFSIZE (65536) /*!< スコアサーバ転送バッファサイズ */
67 * @return 確保したバッファの参照ポインタ
69 static BUF *buf_new(void)
72 p = static_cast<BUF*>(malloc(sizeof(BUF)));
77 p->max_size = BUFSIZE;
78 p->data = static_cast<char*>(malloc(BUFSIZE));
89 * @param b 解放するバッファの参照ポインタ
91 static void buf_delete(BUF *b)
98 * @brief 転送用バッファにデータを追加する
99 * @param buf 追加先バッファの参照ポインタ
104 static int buf_append(BUF *buf, concptr data, size_t size)
106 while (buf->size + size > buf->max_size) {
108 if ((tmp = static_cast<char*>(malloc(buf->max_size * 2))) == NULL)
111 memcpy(tmp, buf->data, buf->max_size);
118 memcpy(buf->data + buf->size, data, size);
125 * @brief 転送用バッファにフォーマット指定した文字列データを追加する
126 * @param buf 追加先バッファの参照ポインタ
127 * @param fmt 文字列フォーマット
130 static int buf_sprintf(BUF *buf, concptr fmt, ...)
137 #if defined(HAVE_VSNPRINTF)
138 ret = vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
140 ret = vsprintf(tmpbuf, fmt, ap);
147 ret = buf_append(buf, tmpbuf, strlen(tmpbuf));
151 size_t read_callback(char *buffer, size_t size, size_t nitems, void *userdata)
153 BUF *buf = static_cast<BUF*>(userdata);
154 const size_t remain = buf->size - buf->read_head;
155 const size_t copy_size = MIN(size * nitems, remain);
157 strncpy(buffer, buf->data + buf->read_head, copy_size);
158 buf->read_head += copy_size;
164 * @brief HTTPによるダンプ内容伝送
166 * @param buf 伝送内容バッファ
167 * @return 送信に成功した場合TRUE、失敗した場合FALSE
169 static bool http_post(concptr url, BUF *buf)
171 bool succeeded = FALSE;
172 CURL *curl = curl_easy_init();
177 struct curl_slist *slist = NULL;
178 slist = curl_slist_append(slist,
181 "Content-Type: text/plain; charset=SHIFT_JIS"
184 "Content-Type: text/plain; charset=EUC-JP"
187 "Content-Type: text/plain; charset=ASCII"
191 curl_easy_setopt(curl, CURLOPT_URL, url);
192 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
195 snprintf(user_agent, sizeof(user_agent), "Hengband %d.%d.%d", FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
196 curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent);
198 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
199 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
201 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
202 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, HTTP_TIMEOUT);
203 curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_TIMEOUT);
205 curl_easy_setopt(curl, CURLOPT_POST, 1);
207 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
208 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10);
209 curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
212 curl_easy_setopt(curl, CURLOPT_READDATA, buf);
213 curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
214 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, buf->size);
216 if (curl_easy_perform(curl) == CURLE_OK) {
218 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
219 if (response_code == 200) {
224 curl_slist_free_all(slist);
225 curl_easy_cleanup(curl);
231 * @brief キャラクタダンプを作って BUFに保存
232 * @param creature_ptr プレーヤーへの参照ポインタ
233 * @param dumpbuf 伝送内容バッファ
236 static errr make_dump(player_type *creature_ptr, BUF *dumpbuf, void (*update_playtime)(void), display_player_pf display_player)
240 GAME_TEXT file_name[1024];
242 /* Open a new file */
243 fff = angband_fopen_temp(file_name, 1024);
246 msg_format("一時ファイル %s を作成できませんでした。", file_name);
248 msg_format("Failed to create temporary file %s.", file_name);
254 /* 一旦一時ファイルを作る。通常のダンプ出力と共通化するため。 */
255 make_character_dump(creature_ptr, fff, update_playtime, display_player);
259 fff = angband_fopen(file_name, "r");
261 while (fgets(buf, 1024, fff)) {
262 (void)buf_sprintf(dumpbuf, "%s", buf);
272 * @brief スクリーンダンプを作成する/ Make screen dump to buffer
273 * @return 作成したスクリーンダンプの参照ポインタ
275 concptr make_screen_dump(player_type *creature_ptr, void (*process_autopick_file_command)(char *))
277 static concptr html_head[] = {
278 "<html>\n<body text=\"#ffffff\" bgcolor=\"#000000\">\n",
282 static concptr html_foot[] = {
284 "</body>\n</html>\n",
289 term_get_size(&wid, &hgt);
293 screen_buf = buf_new();
294 if (screen_buf == NULL)
297 bool old_use_graphics = use_graphics;
298 if (old_use_graphics) {
299 /* Clear -more- prompt first */
302 use_graphics = FALSE;
303 reset_visuals(creature_ptr, process_autopick_file_command);
305 creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
306 handle_stuff(creature_ptr);
309 for (int i = 0; html_head[i]; i++)
310 buf_sprintf(screen_buf, html_head[i]);
312 /* Dump the screen */
313 for (int y = 0; y < hgt; y++) {
316 buf_sprintf(screen_buf, "\n");
319 TERM_COLOR a = 0, old_a = 0;
321 for (int x = 0; x < wid - 1; x++) {
324 /* Get the attr/char */
325 (void)(term_what(x, y, &a, &c));
348 c = (a == 0x09) ? '%' : '#';
354 if ((y == 0 && x == 0) || a != old_a) {
355 rv = angband_color_table[a][1];
356 gv = angband_color_table[a][2];
357 bv = angband_color_table[a][3];
358 buf_sprintf(screen_buf, "%s<font color=\"#%02x%02x%02x\">", ((y == 0 && x == 0) ? "" : "</font>"), rv, gv, bv);
363 buf_sprintf(screen_buf, "%s", cc);
365 buf_sprintf(screen_buf, "%c", c);
369 buf_sprintf(screen_buf, "</font>");
371 for (int i = 0; html_foot[i]; i++)
372 buf_sprintf(screen_buf, html_foot[i]);
374 /* Screen dump size is too big ? */
376 if (screen_buf->size + 1 > SCREEN_BUF_MAX_SIZE) {
379 /* Terminate string */
380 buf_append(screen_buf, "", 1);
382 ret = string_make(screen_buf->data);
386 buf_delete(screen_buf);
388 if (!old_use_graphics)
392 reset_visuals(creature_ptr, process_autopick_file_command);
394 creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
395 handle_stuff(creature_ptr);
400 * @brief スコア転送処理のメインルーチン
401 * @param creature_ptr プレーヤーへの参照ポインタ
402 * @return 正常終了の時0、異常があったら1
403 * @todo メッセージは言語選択の関数マクロで何とかならんか?
405 errr report_score(player_type *creature_ptr, void (*update_playtime)(void), display_player_pf display_player)
411 char seikakutmp[128];
415 sprintf(seikakutmp, "%s%s", ap_ptr->title, (ap_ptr->no ? "の" : ""));
417 sprintf(seikakutmp, "%s ", ap_ptr->title);
420 if (creature_ptr->pclass == CLASS_ELEMENTALIST)
421 realm1_name = get_element_title(creature_ptr->element);
423 realm1_name = realm_names[creature_ptr->realm1];
425 buf_sprintf(score, "name: %s\n", creature_ptr->name);
426 buf_sprintf(score, "version: %s\n", title);
427 buf_sprintf(score, "score: %d\n", calc_score(creature_ptr));
428 buf_sprintf(score, "level: %d\n", creature_ptr->lev);
429 buf_sprintf(score, "depth: %d\n", creature_ptr->current_floor_ptr->dun_level);
430 buf_sprintf(score, "maxlv: %d\n", creature_ptr->max_plv);
431 buf_sprintf(score, "maxdp: %d\n", max_dlv[DUNGEON_ANGBAND]);
432 buf_sprintf(score, "au: %d\n", creature_ptr->au);
433 buf_sprintf(score, "turns: %d\n", turn_real(creature_ptr, current_world_ptr->game_turn));
434 buf_sprintf(score, "sex: %d\n", creature_ptr->psex);
435 buf_sprintf(score, "race: %s\n", rp_ptr->title);
436 buf_sprintf(score, "class: %s\n", cp_ptr->title);
437 buf_sprintf(score, "seikaku: %s\n", seikakutmp);
438 buf_sprintf(score, "realm1: %s\n", realm1_name);
439 buf_sprintf(score, "realm2: %s\n", realm_names[creature_ptr->realm2]);
440 buf_sprintf(score, "killer: %s\n", creature_ptr->died_from);
441 buf_sprintf(score, "-----charcter dump-----\n");
443 make_dump(creature_ptr, score, update_playtime, display_player);
446 buf_sprintf(score, "-----screen shot-----\n");
447 buf_append(score, screen_dump, strlen(screen_dump));
452 bool succeeded = FALSE;
456 prt(_("スコア送信中...", "Sending the score..."), 0, 0);
459 if (http_post(SCORE_PATH, score)) {
462 prt(_("スコア・サーバへの送信に失敗しました。", "Failed to send to the score server."), 0, 0);
465 if (!get_check_strict(creature_ptr, _("もう一度接続を試みますか? ", "Try again? "), CHECK_NO_HISTORY)) {
473 return succeeded ? 0 : 1;
476 concptr screen_dump = NULL;
477 #endif /* WORLD_SCORE */