OSDN Git Service

[Refactor] #40413 Separated asking-player.c/h from util.c/h
[hengband/hengband.git] / src / io / report.c
1 /*!
2  * @file report.c
3  * @brief スコアサーバ転送機能の実装
4  * @date 2014/07/14
5  * @author Hengband Team
6  */
7
8 #include "io/report.h"
9 #include "core/asking-player.h"
10 #include "core/stuff-handler.h"
11 #include "core/turn-compensator.h"
12 #include "core/visuals-reseter.h"
13 #include "dungeon/dungeon.h"
14 #include "floor/floor.h"
15 #include "game-option/special-options.h"
16 #include "io-dump/character-dump.h"
17 #include "io/inet.h"
18 #include "io/input-key-acceptor.h"
19 #include "player/player-personality.h"
20 #include "system/angband-version.h"
21 #include "term/gameterm.h"
22 #include "util/angband-files.h"
23 #include "view/display-messages.h"
24 #include "world/world.h"
25
26 #ifdef WORLD_SCORE
27
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include <ctype.h>
31 #include <string.h>
32
33 #if defined(WINDOWS)
34 #include <winsock.h>
35 #else
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #include <sys/time.h>
41
42 #include <setjmp.h>
43 #include <signal.h>
44 #endif
45
46 concptr screen_dump = NULL;
47
48 /*
49  * internet resource value
50  */
51 #define HTTP_PROXY ""                   /*!< デフォルトのプロキシURL / Default proxy url */
52 #define HTTP_PROXY_PORT 0               /*!< デフォルトのプロキシポート / Default proxy port */
53 #define HTTP_TIMEOUT    20              /*!< デフォルトのタイムアウト時間(秒) / Timeout length (second) */
54 #define SCORE_SERVER "hengband.osdn.jp" /*!< デフォルトのスコアサーバURL / Default score server url */
55 #define SCORE_PORT 80                   /*!< デフォルトのスコアサーバポート / Default score server port */
56
57 #ifdef JP
58 #define SCORE_PATH "http://hengband.osdn.jp/score/register_score.php" /*!< スコア開示URL */
59 #else
60 #define SCORE_PATH "http://moon.kmc.gr.jp/hengband/hengscore-en/score.cgi" /*!< スコア開示URL */
61 #endif
62
63  /*
64   * simple buffer library
65   */
66 typedef struct {
67         size_t max_size;
68         size_t size;
69         char *data;
70 } BUF;
71
72 #define BUFSIZE (65536) /*!< スコアサーバ転送バッファサイズ */
73
74 /*!
75  * @brief 転送用バッファの確保
76  * @return 確保したバッファの参照ポインタ
77  */
78 static BUF* buf_new(void)
79 {
80         BUF *p;
81         p = malloc(sizeof(BUF));
82         if (!p) return NULL;
83
84         p->size = 0;
85         p->max_size = BUFSIZE;
86         p->data = malloc(BUFSIZE);
87         if (!p->data)
88         {
89                 free(p);
90                 return NULL;
91         }
92
93         return p;
94 }
95
96
97 /*!
98  * @brief 転送用バッファの解放
99  * @param b 解放するバッファの参照ポインタ
100  */
101 static void buf_delete(BUF *b)
102 {
103         free(b->data);
104         free(b);
105 }
106
107
108 /*!
109  * @brief 転送用バッファにデータを追加する
110  * @param buf 追加先バッファの参照ポインタ
111  * @param data 追加元データ
112  * @param size 追加サイズ
113  * @return 追加後のバッファ容量
114  */
115 static int buf_append(BUF *buf, concptr data, size_t size)
116 {
117         while (buf->size + size > buf->max_size)
118         {
119                 char *tmp;
120                 if ((tmp = malloc(buf->max_size * 2)) == NULL) return -1;
121
122                 memcpy(tmp, buf->data, buf->max_size);
123                 free(buf->data);
124
125                 buf->data = tmp;
126
127                 buf->max_size *= 2;
128         }
129         memcpy(buf->data + buf->size, data, size);
130         buf->size += size;
131
132         return buf->size;
133 }
134
135
136 /*!
137  * @brief 転送用バッファにフォーマット指定した文字列データを追加する
138  * @param buf 追加先バッファの参照ポインタ
139  * @param fmt 文字列フォーマット
140  * @return 追加後のバッファ容量
141  */
142 static int buf_sprintf(BUF *buf, concptr fmt, ...)
143 {
144         int             ret;
145         char    tmpbuf[8192];
146         va_list ap;
147
148         va_start(ap, fmt);
149 #if defined(HAVE_VSNPRINTF)
150         ret = vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
151 #else
152         ret = vsprintf(tmpbuf, fmt, ap);
153 #endif
154         va_end(ap);
155
156         if (ret < 0) return -1;
157
158         ret = buf_append(buf, tmpbuf, strlen(tmpbuf));
159         return ret;
160 }
161
162
163 /*!
164  * @brief HTTPによるダンプ内容伝送
165  * @param sd ソケットID
166  * @param url 伝送先URL
167  * @param buf 伝送内容バッファ
168  * @return なし
169  */
170 static bool http_post(int sd, concptr url, BUF *buf)
171 {
172         BUF *output;
173         char response_buf[1024] = "";
174         concptr HTTP_RESPONSE_CODE_OK = "HTTP/1.1 200 OK";
175
176         output = buf_new();
177         buf_sprintf(output, "POST %s HTTP/1.0\r\n", url);
178         buf_sprintf(output, "User-Agent: Hengband %d.%d.%d\r\n",
179                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
180
181         buf_sprintf(output, "Content-Length: %d\r\n", buf->size);
182         buf_sprintf(output, "Content-Encoding: binary\r\n");
183 #ifdef JP
184 #ifdef SJIS
185         buf_sprintf(output, "Content-Type: text/plain; charset=SHIFT_JIS\r\n");
186 #endif
187 #ifdef EUC
188         buf_sprintf(output, "Content-Type: text/plain; charset=EUC-JP\r\n");
189 #endif
190 #else
191         buf_sprintf(output, "Content-Type: text/plain; charset=ASCII\r\n");
192 #endif
193         buf_sprintf(output, "\r\n");
194         buf_append(output, buf->data, buf->size);
195
196         soc_write(sd, output->data, output->size);
197
198         soc_read(sd, response_buf, sizeof(response_buf));
199
200         return strncmp(response_buf, HTTP_RESPONSE_CODE_OK, strlen(HTTP_RESPONSE_CODE_OK)) == 0;
201 }
202
203
204 /*!
205  * @brief キャラクタダンプを作って BUFに保存
206  * @param creature_ptr プレーヤーへの参照ポインタ
207  * @param dumpbuf 伝送内容バッファ
208  * @return エラーコード
209  */
210 static errr make_dump(player_type *creature_ptr, BUF* dumpbuf, void(*update_playtime)(void), display_player_pf display_player, map_name_pf map_name)
211 {
212         char            buf[1024];
213         FILE *fff;
214         GAME_TEXT file_name[1024];
215
216         /* Open a new file */
217         fff = angband_fopen_temp(file_name, 1024);
218         if (!fff)
219         {
220 #ifdef JP
221                 msg_format("一時ファイル %s を作成できませんでした。", file_name);
222 #else
223                 msg_format("Failed to create temporary file %s.", file_name);
224 #endif
225                 msg_print(NULL);
226                 return 1;
227         }
228
229         /* 一旦一時ファイルを作る。通常のダンプ出力と共通化するため。 */
230         make_character_dump(creature_ptr, fff, update_playtime, display_player, map_name);
231         angband_fclose(fff);
232
233         /* Open for read */
234         fff = angband_fopen(file_name, "r");
235
236         while (fgets(buf, 1024, fff))
237         {
238                 (void)buf_sprintf(dumpbuf, "%s", buf);
239         }
240         angband_fclose(fff);
241         fd_kill(file_name);
242
243         /* Success */
244         return 0;
245 }
246
247
248 /*!
249  * @brief スクリーンダンプを作成する/ Make screen dump to buffer
250  * @return 作成したスクリーンダンプの参照ポインタ
251  */
252 concptr make_screen_dump(player_type *creature_ptr, void(*process_autopick_file_command)(char*))
253 {
254         static concptr html_head[] = {
255                 "<html>\n<body text=\"#ffffff\" bgcolor=\"#000000\">\n",
256                 "<pre>",
257                 0,
258         };
259         static concptr html_foot[] = {
260                 "</pre>\n",
261                 "</body>\n</html>\n",
262                 0,
263         };
264
265         int wid, hgt;
266         Term_get_size(&wid, &hgt);
267
268         /* Alloc buffer */
269         BUF *screen_buf;
270         screen_buf = buf_new();
271         if (screen_buf == NULL) return (NULL);
272
273         bool old_use_graphics = use_graphics;
274         if (old_use_graphics)
275         {
276                 /* Clear -more- prompt first */
277                 msg_print(NULL);
278
279                 use_graphics = FALSE;
280                 reset_visuals(creature_ptr, process_autopick_file_command);
281
282                 creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
283                 handle_stuff(creature_ptr);
284         }
285
286         for (int i = 0; html_head[i]; i++)
287                 buf_sprintf(screen_buf, html_head[i]);
288
289         /* Dump the screen */
290         for (int y = 0; y < hgt; y++)
291         {
292                 /* Start the row */
293                 if (y != 0)
294                         buf_sprintf(screen_buf, "\n");
295
296                 /* Dump each row */
297                 TERM_COLOR a = 0, old_a = 0;
298                 SYMBOL_CODE c = ' ';
299                 for (int x = 0; x < wid - 1; x++)
300                 {
301                         int rv, gv, bv;
302                         concptr cc = NULL;
303                         /* Get the attr/char */
304                         (void)(Term_what(x, y, &a, &c));
305
306                         switch (c)
307                         {
308                         case '&': cc = "&amp;"; break;
309                         case '<': cc = "&lt;"; break;
310                         case '>': cc = "&gt;"; break;
311                         case '"': cc = "&quot;"; break;
312                         case '\'': cc = "&#39;"; break;
313 #ifdef WINDOWS
314                         case 0x1f: c = '.'; break;
315                         case 0x7f: c = (a == 0x09) ? '%' : '#'; break;
316 #endif
317                         }
318
319                         a = a & 0x0F;
320                         if ((y == 0 && x == 0) || a != old_a) {
321                                 rv = angband_color_table[a][1];
322                                 gv = angband_color_table[a][2];
323                                 bv = angband_color_table[a][3];
324                                 buf_sprintf(screen_buf, "%s<font color=\"#%02x%02x%02x\">",
325                                         ((y == 0 && x == 0) ? "" : "</font>"), rv, gv, bv);
326                                 old_a = a;
327                         }
328
329                         if (cc)
330                                 buf_sprintf(screen_buf, "%s", cc);
331                         else
332                                 buf_sprintf(screen_buf, "%c", c);
333                 }
334         }
335
336         buf_sprintf(screen_buf, "</font>");
337
338         for (int i = 0; html_foot[i]; i++)
339                 buf_sprintf(screen_buf, html_foot[i]);
340
341         /* Screen dump size is too big ? */
342         concptr ret;
343         if (screen_buf->size + 1 > SCREEN_BUF_MAX_SIZE)
344         {
345                 ret = NULL;
346         }
347         else
348         {
349                 /* Terminate string */
350                 buf_append(screen_buf, "", 1);
351
352                 ret = string_make(screen_buf->data);
353         }
354
355         /* Free buffer */
356         buf_delete(screen_buf);
357
358         if (!old_use_graphics) return ret;
359
360         use_graphics = TRUE;
361         reset_visuals(creature_ptr, process_autopick_file_command);
362
363         creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
364         handle_stuff(creature_ptr);
365         return ret;
366 }
367
368
369 /*!
370  * todo メッセージは言語選択の関数マクロで何とかならんか?
371  * @brief スコア転送処理のメインルーチン
372  * @param creature_ptr プレーヤーへの参照ポインタ
373  * @return 正常終了の時0、異常があったら1
374  */
375 errr report_score(player_type *creature_ptr, void(*update_playtime)(void), display_player_pf display_player, map_name_pf map_name)
376 {
377 #ifdef WINDOWS
378         WSADATA wsaData;
379         WORD wVersionRequested = (WORD)((1) | (1 << 8));
380 #endif
381
382         BUF *score;
383         score = buf_new();
384
385         char seikakutmp[128];
386 #ifdef JP
387         sprintf(seikakutmp, "%s%s", ap_ptr->title, (ap_ptr->no ? "の" : ""));
388 #else
389         sprintf(seikakutmp, "%s ", ap_ptr->title);
390 #endif
391
392         buf_sprintf(score, "name: %s\n", creature_ptr->name);
393 #ifdef JP
394         buf_sprintf(score, "version: 変愚蛮怒 %d.%d.%d\n",
395                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
396 #else
397         buf_sprintf(score, "version: Hengband %d.%d.%d\n",
398                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
399 #endif
400         buf_sprintf(score, "score: %d\n", calc_score(creature_ptr));
401         buf_sprintf(score, "level: %d\n", creature_ptr->lev);
402         buf_sprintf(score, "depth: %d\n", creature_ptr->current_floor_ptr->dun_level);
403         buf_sprintf(score, "maxlv: %d\n", creature_ptr->max_plv);
404         buf_sprintf(score, "maxdp: %d\n", max_dlv[DUNGEON_ANGBAND]);
405         buf_sprintf(score, "au: %d\n", creature_ptr->au);
406         buf_sprintf(score, "turns: %d\n", turn_real(creature_ptr, current_world_ptr->game_turn));
407         buf_sprintf(score, "sex: %d\n", creature_ptr->psex);
408         buf_sprintf(score, "race: %s\n", rp_ptr->title);
409         buf_sprintf(score, "class: %s\n", cp_ptr->title);
410         buf_sprintf(score, "seikaku: %s\n", seikakutmp);
411         buf_sprintf(score, "realm1: %s\n", realm_names[creature_ptr->realm1]);
412         buf_sprintf(score, "realm2: %s\n", realm_names[creature_ptr->realm2]);
413         buf_sprintf(score, "killer: %s\n", creature_ptr->died_from);
414         buf_sprintf(score, "-----charcter dump-----\n");
415
416         make_dump(creature_ptr, score, update_playtime, display_player, map_name);
417
418         if (screen_dump)
419         {
420                 buf_sprintf(score, "-----screen shot-----\n");
421                 buf_append(score, screen_dump, strlen(screen_dump));
422         }
423
424 #ifdef WINDOWS
425         if (WSAStartup(wVersionRequested, &wsaData))
426         {
427                 msg_print("Report: WSAStartup failed.");
428 #ifdef WINDOWS
429                 WSACleanup();
430 #endif
431                 return 1;
432         }
433 #endif
434
435         Term_clear();
436
437         int sd;
438         while (TRUE)
439         {
440                 char buff[160];
441 #ifdef JP
442                 prt("接続中...", 0, 0);
443 #else
444                 prt("connecting...", 0, 0);
445 #endif
446                 Term_fresh();
447
448                 /* プロキシを設定する */
449                 set_proxy(HTTP_PROXY, HTTP_PROXY_PORT);
450
451                 /* Connect to the score server */
452                 sd = connect_server(HTTP_TIMEOUT, SCORE_SERVER, SCORE_PORT);
453
454
455                 if (sd < 0) {
456 #ifdef JP
457                         sprintf(buff, "スコア・サーバへの接続に失敗しました。(%s)", soc_err());
458 #else
459                         sprintf(buff, "Failed to connect to the score server.(%s)", soc_err());
460 #endif
461                         prt(buff, 0, 0);
462                         (void)inkey();
463
464 #ifdef JP
465                         if (!get_check_strict(creature_ptr, "もう一度接続を試みますか? ", CHECK_NO_HISTORY))
466 #else
467                         if (!get_check_strict(creature_ptr, "Try again? ", CHECK_NO_HISTORY))
468 #endif
469                         {
470 #ifdef WINDOWS
471                                 WSACleanup();
472 #endif
473                                 return 1;
474                         }
475
476                         continue;
477                 }
478
479 #ifdef JP
480                 prt("スコア送信中...", 0, 0);
481 #else
482                 prt("Sending the score...", 0, 0);
483 #endif
484                 Term_fresh();
485
486                 if (!http_post(sd, SCORE_PATH, score)) {
487                         disconnect_server(sd);
488 #ifdef JP
489                         sprintf(buff, "スコア・サーバへの送信に失敗しました。");
490 #else
491                         sprintf(buff, "Failed to send to the score server.");
492 #endif
493                         prt(buff, 0, 0);
494                         (void)inkey();
495
496 #ifdef JP
497                         if (!get_check_strict(creature_ptr, "もう一度接続を試みますか? ", CHECK_NO_HISTORY))
498 #else
499                         if (!get_check_strict(creature_ptr, "Try again? ", CHECK_NO_HISTORY))
500 #endif
501                         {
502 #ifdef WINDOWS
503                                 WSACleanup();
504 #endif
505                                 return 1;
506                         }
507
508                         continue;
509                 }
510
511                 disconnect_server(sd);
512                 break;
513         }
514
515 #ifdef WINDOWS
516         WSACleanup();
517 #endif
518
519         return 0;
520 }
521 #endif /* WORLD_SCORE */