OSDN Git Service

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