OSDN Git Service

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