OregonCore  revision 3611e8a-git
Your Favourite TBC server
Console.cpp
Go to the documentation of this file.
1 
2 #include "Console.h"
3 #include "Log.h"
4 #include "World.h"
5 #include "TicketMgr.h"
6 #include "revision.h"
7 
8 #ifdef __PDCURSES__
9 # undef A_PROTECT
10 # define A_PROTECT A_NORMAL
11 # define getmouse nc_getmouse
12 # define resizeterm resize_term
13 # define SCROLLUP_MASK BUTTON4_PRESSED
14 # define SCROLLDN_MASK BUTTON5_PRESSED
15 #else
16 # define SCROLLUP_MASK 0x00080000
17 # define SCROLLDN_MASK 0x08000080
18 #endif
19 
20 #define TermColor(x) COLOR_PAIR(x+1)
21 
23 
24 static const char sOregonLogo[] =
25 {
26  "MMMMMMMMMMM "
27  "MMP dMM "
28  "M' .mmm. `M "
29  "M MMMMM M 88d888b. .d8888b. .d8888b. .d8888b. 88d888b."
30  "M MMMMM M 88' `88 88ooood8 88' `88 88' `88 88' `88"
31  "M. `MMM' .M 88 88. ... 88. .88 88. .88 88 88"
32  "MMb dMM dP `88888P' `8888P88 `88888P' dP dP"
33  "MMMMMMMMMMM .88 "
34  " d8888P"
35 };
36 static const unsigned int sOregonLogoRows = 9;
37 static const unsigned int sOregonLogoCols = 56;
38 
39 static const char* Menu[] =
40 {
41  "Run a Command",
42  "Toggle Output",
43  "-------------",
44  " Halt Server ",
45 };
46 static const int MenuItems = sizeof(Menu) / sizeof(*Menu);
47 
48 #if PLATFORM == PLATFORM_WINDOWS
49 BOOL WINAPI HandleConsoleInterrupt(DWORD)
50 {
51  endwin();
52  raise(SIGINT);
53  return TRUE;
54 }
55 #endif
56 
57 Console::Console() : m_IamEnabled(false), m_loggerFd(0), m_logoWindow(0), m_loadWindow(0)
58 {
59  SetTitle("OregonCore");
60  #if PLATFORM == PLATFORM_WINDOWS
61  SetConsoleCtrlHandler(&HandleConsoleInterrupt, TRUE);
62  #endif
63 }
64 
66 {
67  if (!m_IamEnabled)
68  return;
69 
70  for (std::set<Window*>::const_iterator it = m_windows.begin(); it != m_windows.end(); )
71  {
72  DestroyWindow(*it);
73  it = m_windows.begin();
74  }
75 
76  endwin();
77 
78  if (m_loggerFd)
79  #if PLATFORM == PLATFORM_WINDOWS
80  CloseHandle(m_loggerFd);
81  #else
82  close(m_loggerFd);
83  #endif
84 }
85 
87 {
88  m_IamEnabled = true;
89 
90  initscr(); // init curses
91  cbreak(); // turn off line buffering
92  noecho(); // turn off echoing of chars by terminal
93  keypad(stdscr, TRUE); // enable use of F1-F12 keys, arrows, etc.
94  curs_set(0); // try to make the cursor invisible
95  idlok(stdscr, TRUE); // allow terminal controls line ins/del
96  idcok(stdscr, TRUE); // allow terminal controls char ins/del
97  scrollok(stdscr, TRUE); // allow scrolling
98  leaveok(stdscr, TRUE); // dont move cursor (performance)
99  nonl(); // disable new line feed translating
100  start_color(); // initialize colors
101 
102  use_default_colors();
103  if (has_colors())
104  for (int i = 1; i <= COLORS; i++)
105  init_pair(i + 1, i, -1);
106 
107  mousemask(ALL_MOUSE_EVENTS & ~REPORT_MOUSE_POSITION, NULL); // allow mouse interaction
108  mouseinterval(0);
109 
110  int width = sConfig.GetIntDefault("Console.Width", 0);
111  int height = sConfig.GetIntDefault("Console.Height", 0);
112 
113  if (width > 0 && height > 0)
114  resizeterm(height, width);
115 
116  if (!m_logoWindow)
117  {
118  // win height width y x
119  m_logoWindow = MakeWindow(sOregonLogoRows, sOregonLogoCols, 1, COLS / 2 - sOregonLogoCols / 2);
120  m_loadWindow = MakeWindow(3, sOregonLogoCols, 2 + sOregonLogoRows, COLS / 2 - sOregonLogoCols / 2);
121 
122  int rows = 0xFFFF / COLS;
123  m_logViewer = newpad(rows, COLS);
124  idlok(m_logViewer, TRUE);
125  idcok(m_logViewer, TRUE);
126  scrollok(m_logViewer, TRUE);
127  wmove(m_logViewer, rows - 1, COLS - 1);
128  wprintw(m_logViewer, " ");
129 
130  m_cmdOutput = dupwin(m_logViewer);
131  }
132 
133  Refresh();
134 
135  // we abuse stderr to bring us data from logger
136  #if PLATFORM == PLATFORM_WINDOWS
137  HANDLE writer, reader;
138  char pipeName[MAX_PATH];
139  sprintf(pipeName, "\\\\.\\Pipe\\LocalOCAnon.%u", GetCurrentProcessId());
140  SetLastError(0);
141  reader = CreateNamedPipeA(pipeName, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE, 1, 4096, 0xFFFF, 1000, NULL);
142  writer = CreateFileA(pipeName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, NULL);
143 
144  if (GetLastError())
145  {
146  if (!reader || reader == INVALID_HANDLE_VALUE)
147  CloseHandle(reader);
148  if (!writer || writer == INVALID_HANDLE_VALUE)
149  CloseHandle(writer);
150  fclose(stderr);
151  return;
152  }
153 
154  SetStdHandle(STD_ERROR_HANDLE, writer);
155  //stderr->_file = _open_osfhandle((long) writer, _O_TEXT);
156  dup2(_open_osfhandle((long) writer, 0), fileno(stderr));
157  m_loggerFd = reader;
158  #else
159  int fds[2];
160  if (!pipe(fds))
161  {
162  // 0 - reader, 1 - writer
163  if (-1 == dup2(fds[1], STDERR_FILENO))
164  fclose(stderr);
165  else
166  {
167  fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK | O_CLOEXEC);
168  fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | O_NONBLOCK | O_CLOEXEC);
169  m_loggerFd = fds[0];
170 
171  setvbuf(stderr, NULL, _IOLBF, 0);
172  }
173  }
174  else
175  fclose(stderr);
176  #endif
177 }
178 
180 {
181  wrefresh(stdscr);
182 
183  for (std::set<Window*>::const_iterator it = m_windows.begin(); it != m_windows.end(); it++)
184  wrefresh(*it);
185 }
186 
188 {
189  endwin();
190  m_IamEnabled = false;
191 }
192 
193 Window* Console::MakeWindow(int h, int w, int y, int x)
194 {
195  Window* win = newwin(h, w, y, x);
196  leaveok(win, TRUE);
197  m_windows.insert(win);
198  return win;
199 }
200 
202 {
203  if (!win)
204  return;
205 
206  werase(win); // make it blank
207  wrefresh(win); // apply
208  m_windows.erase(win);
209  delwin(win);
210 }
211 
212 void Console::ResizeWindow(Window* win, int h, int w, int y, int x)
213 {
214  mvwin(win, y, x);
215  wresize(win, h, w);
216 }
217 
219 {
220  int ch = getch();
221  if (ch == KEY_MOUSE)
222  {
223  MEVENT event;
224  if (getmouse(&event) == OK)
225  {
226  if (event.bstate & SCROLLUP_MASK)
227  ch = KEY_SR; // scroll up
228  else if (event.bstate & SCROLLDN_MASK)
229  ch = KEY_SF; // scroll down
230  }
231  }
232  return ch;
233 }
234 
236 {
237  if (sConfig.GetBoolDefault("BeepAtStart", true))
238  sConsole.Beep();
239 
240  sConsole.MainLoop();
241 }
242 
244 {
246 
247  int MenuActiveItem = 0;
248  time_t startTime = time(0); // we use our own timer due to thread-safety
249 
250  // height width y x
251  Window* menuWindow = MakeWindow(MenuItems + 2, 19, 1 + sOregonLogoRows + 1, COLS / 2 - 10 - 2);
252  Window* infoWindow = MakeWindow(4, sOregonLogoCols, 5 + sOregonLogoRows + MenuItems, COLS / 2 - sOregonLogoCols / 2);
253 
254  flushinp();
255 
256  wattron(menuWindow, A_BOLD | TermColor(COLOR_CYAN));
257  wborder(menuWindow, '|', '|', '-', '-', '+', '+', '+', '+');
258  wattroff(menuWindow, A_BOLD | TermColor(COLOR_CYAN));
259 
260  DrawLogo();
261 
262  while (!World::IsStopped())
263  {
264  // draw menu
265  for (int i = 0; i < MenuItems; i++)
266  {
267  if (MenuActiveItem == i)
268  {
269  wattron(menuWindow, A_BOLD | TermColor(COLOR_GREEN));
270  mvwprintw(menuWindow, i + 1, 1, "* %s *", Menu[i]);
271  wattroff(menuWindow, A_BOLD | TermColor(COLOR_GREEN));
272  }
273  else if (Menu[i][0] == '-')
274  mvwprintw(menuWindow, i + 1, 1, "--%s--", Menu[i]);
275  else
276  mvwprintw(menuWindow, i + 1, 1, " %s ", Menu[i]);
277  }
278 
279  // draw info
280  enum InfoValue
281  {
282  INFO_EMPTY,
283 
284  INFO_PLAYERS_ONLINE,
285  INFO_PLAYERS_QUEUED,
286  INFO_PLAYERS_MAX,
287 
288  INFO_REVISION,
289  INFO_LOGMASK,
290  INFO_UPTIME,
291  INFO_TICKETS
292  };
293 
294  struct
295  {
296  int y;
297  int x;
298  const char* type;
299  InfoValue value;
300  } InfoTable[]
301  =
302  {
303  { 0, 0, "Players:", INFO_PLAYERS_ONLINE },
304  { 1, 0, " ", INFO_PLAYERS_QUEUED },
305  { 2, 0, " ", INFO_PLAYERS_MAX, },
306  { 3, 0, " ", INFO_EMPTY, },
307 
308  { 0, 34, "Revision:", INFO_REVISION, },
309  { 1, 34, "LogMask:", INFO_LOGMASK, },
310  { 2, 34, "Uptime: ", INFO_UPTIME, },
311  { 3, 34, "Tickets: ", INFO_TICKETS, }
312  };
313 
314  for (uint32 i = 0; i < sizeof(InfoTable) / sizeof(*InfoTable); i++)
315  {
316  wmove(infoWindow, InfoTable[i].y, InfoTable[i].x);
317  wattron(infoWindow, A_BOLD | TermColor(COLOR_GREEN));
318  wprintw(infoWindow, "%s", InfoTable[i].type);
319  wattroff(infoWindow, A_BOLD | TermColor(COLOR_GREEN));
320  switch (InfoTable[i].value)
321  {
322  case INFO_PLAYERS_ONLINE:
323  wprintw(infoWindow, " %u (online)", sWorld.GetActiveSessionCount());
324  break;
325  case INFO_PLAYERS_QUEUED:
326  wprintw(infoWindow, " %u (queued)", sWorld.GetQueuedSessionCount());
327  break;
328  case INFO_PLAYERS_MAX:
329  wprintw(infoWindow, " %u (max)", sWorld.GetMaxActiveSessionCount() + sWorld.GetMaxQueuedSessionCount());
330  break;
331  case INFO_REVISION:
332  wprintw(infoWindow, " %s", _REVISION);
333  break;
334  case INFO_LOGMASK:
335  wprintw(infoWindow, " %lu", sLog.GetLogMask());
336  break;
337  case INFO_UPTIME:
338  {
339  time_t diff = time(0) - startTime;
340  uint32 mins = diff / 60;
341  uint32 hours = mins / 60;
342  uint32 days = hours / 24;
343  wprintw(infoWindow, " %ud %uh %um", days, hours % 24, mins % 60);
344  }
345  break;
346  case INFO_TICKETS:
347  wprintw(infoWindow, " %lu", ticketmgr.GM_TicketList.size());
348  default:
349  break;
350  }
351  }
352 
353  wrefresh(m_logoWindow);
354  wrefresh(menuWindow);
355  wrefresh(infoWindow);
356 
357  UpdateLog();
358 
359  // align timeout to the next minute
360  timeout((60 - ((time(0) - startTime) % 60)) * 1000);
361  int ch = GetChar();
362 
363  switch (ch)
364  {
365  case KEY_UP:
366  MenuActiveItem = (MenuActiveItem == 0) ? MenuItems - 1 : (MenuActiveItem - 1);
367  if (Menu[MenuActiveItem][0] == '-')
368  MenuActiveItem--;
369  break;
370  case KEY_DOWN:
371  MenuActiveItem = (MenuActiveItem >= MenuItems - 1) ? 0 : (MenuActiveItem + 1);
372  if (Menu[MenuActiveItem][0] == '-')
373  MenuActiveItem++;
374  break;
375  case KEY_ENTER:
376  case '\n':
377  case '\r':
378 
379  switch (MenuActiveItem)
380  {
381  case 0: /* Run a Command */
382  RunCommandLoop();
383  break;
384  case 1: /* Real-time logs */
385  RunLogViewLoop();
386  break;
387  case 3: /* shutdown */
388  endwin();
389  raise(SIGINT);
390  break;
391  }
392 
393  /* Fallthrough */
394  case KEY_RESIZE:
395 
396  erase();
397 
398  // win height width y x
399  ResizeWindow(m_logoWindow, sOregonLogoRows, sOregonLogoCols, 1, COLS / 2 - sOregonLogoCols / 2);
400  ResizeWindow(menuWindow, MenuItems + 2, 19, 1 + sOregonLogoRows + 1, std::max<int>(0, COLS / 2 - 10 - 2));
401  ResizeWindow(infoWindow, 4, sOregonLogoCols, 5 + sOregonLogoRows + MenuItems, COLS / 2 - sOregonLogoCols / 2);
402 
403  wattron(menuWindow, A_BOLD | TermColor(COLOR_CYAN));
404  wborder(menuWindow, '|', '|', '-', '-', '+', '+', '+', '+');
405  wattroff(menuWindow, A_BOLD | TermColor(COLOR_CYAN));
406 
407  Refresh();
408  DrawLogo();
409  break;
410  default:
411  break;;
412  }
413  }
414 
415  DestroyWindow(menuWindow);
416  DestroyWindow(infoWindow);
417 }
418 
419 enum
420 {
421  CMD_FINISHED = (1 << 0),
422  CMD_SUCCESS = (1 << 1)
423 };
424 
425 struct CBArg
426 {
428  volatile long status;
429  bool colored;
430 };
431 
432 static void PrintCommandResultCallback(void* data, const char* msg)
433 {
434  Window* output = reinterpret_cast<CBArg*>(data)->win;
435  if (reinterpret_cast<CBArg*>(data)->colored)
436  wattrset(output, A_PROTECT | A_BOLD | TermColor(COLOR_WHITE));
437  else
438  wattrset(output, A_PROTECT);
439  wprintw(output, "%s", msg);
440  wattrset(output, A_NORMAL);
441 }
442 
443 static void CommandFinishedCallback(void* data, bool success)
444 {
445  // we set first bit to true - command finished
446  // we set second bit to result (success)
447  // we try to do this atomically ('long' should be of native size)
448 
449  if (success)
450  reinterpret_cast<CBArg*>(data)->status = CMD_FINISHED | CMD_SUCCESS;
451  else
452  reinterpret_cast<CBArg*>(data)->status = CMD_FINISHED;
453 }
454 
456 {
457  History::iterator historyCur = m_cmdHistory.begin();
458  if (m_cmdHistory.size())
459  std::advance(historyCur, m_cmdHistory.size() - 1);
460 
461  int no = 1;
462 
463  int lineWidth = COLS - (sizeof("Oregon>") - 1);
464  Window* cmdLine = MakeWindow(1, lineWidth, LINES - 1, (sizeof("Oregon>") - 1));
465 
466  erase();
467  curs_set(1);
468 
469  attron(A_BOLD | TermColor(COLOR_GREEN));
470  mvprintw(LINES - 1, 0, "Oregon> ");
471  attroff(A_BOLD | TermColor(COLOR_GREEN));
472  wattrset(cmdLine, A_PROTECT | TermColor(COLOR_WHITE));
473 
474  int y, mx, my;
475  int pageSize = LINES - 1;
476  getmaxyx(m_cmdOutput, my, mx);
477  y = my - 1 - pageSize;
478 
479  leaveok(cmdLine, FALSE);
480  wmove(cmdLine, 0, 0);
481 
482  pnoutrefresh(m_cmdOutput, y, 0, 0, 0, LINES - 2, COLS);
483  wrefresh(stdscr);
484  wrefresh(cmdLine);
485 
486  bool update = true;
487 
488  std::string buffer = "";
489 
490  while (!World::IsStopped())
491  {
492  if (update)
493  {
494  pnoutrefresh(m_cmdOutput, y, 0, 0, 0, LINES - 2, COLS);
495 
496  attron(A_BOLD | TermColor(COLOR_GREEN));
497  mvprintw(LINES - 1, 0, "Oregon> ");
498  attroff(A_BOLD | TermColor(COLOR_GREEN));
499 
500  wrefresh(stdscr);
501 
502  update = false;
503  }
504 
505  werase(cmdLine);
506  wrefresh(cmdLine);
507  mvwprintw(cmdLine, 0, 0, "%s", buffer.c_str() + std::max<int>(0, (buffer.size() - (lineWidth - 1))));
508  wmove(cmdLine, 0, std::min<size_t>(lineWidth - 1, buffer.size()));
509  wrefresh(cmdLine);
510 
511  int ch = GetChar();
512  if (ch >= 0x20 && ch < 0x7F)
513  {
514  if (buffer.empty() && ch != '.')
515  buffer.append(1, '.');
516  buffer.append(1, ch);
517  }
518  else if (ch == KEY_UP)
519  {
520  historyCur--;
521  if (historyCur != m_cmdHistory.end())
522  buffer = *historyCur;
523  else
524  buffer.clear();
525  }
526  else if (ch == KEY_DOWN)
527  {
528  historyCur++;
529  if (historyCur != m_cmdHistory.end())
530  buffer = *historyCur;
531  else
532  buffer.clear();
533  }
534  else if (ch == KEY_BACKSPACE || ch == 0x7F || ch == 0x08)
535  {
536  if (buffer.size())
537  buffer.resize(buffer.size() - 1);
538  }
539  else if (ch == KEY_PPAGE) // page up
540  {
541  update = true;
542  y = std::max<int>(0, y - pageSize);
543  }
544  else if (ch == KEY_NPAGE) // page down
545  {
546  update = true;
547  y = std::min<int>(my - 1 - pageSize, y + pageSize);
548  }
549  else if (ch == KEY_SR) // scroll up
550  {
551  update = true;
552  y = std::max<int>(0, y - 1);
553  }
554  else if (ch == KEY_SF) // scroll down
555  {
556  update = true;
557  y = std::min<int>(my - 1 - pageSize, y + 1);
558  }
559  else if ((ch == KEY_ENTER || ch == '\n' || ch == '\r'))
560  {
561  if (buffer.empty() || buffer == ".exit" || buffer == ".quit")
562  break;
563 
564  curs_set(0);
565 
566  CBArg result;
567  result.win = m_cmdOutput;
568  result.status = 0;
569  result.colored = (no ^= 1);
570 
571  sWorld.QueueCliCommand(new CliCommandHolder(&result, buffer.c_str(), &PrintCommandResultCallback, &CommandFinishedCallback));
572 
573  /* command is issued we now block until command is executed, to prevent crash in PrintCommandResultCallback:
574  when server shuts down and we destroy output window before last World::Update() which calls PrintCmdResCB;
575  also this ensures thread-safety between curses calls */
576  do
578  while (!(result.status & CMD_FINISHED) && !World::IsStopped());
579 
580  #if OREGON_DEBUG
581  if (!(result.status & CMD_SUCCESS))
582  {
583  wattron(m_cmdOutput, A_BOLD | TermColor(COLOR_RED));
584  wprintw(m_cmdOutput, "Command failed :(\n");
585  wattroff(m_cmdOutput, A_BOLD | TermColor(COLOR_RED));
586  }
587  #endif
588 
589  update = true;
590 
591  m_cmdHistory.push_back(buffer);
592  historyCur = m_cmdHistory.begin();
593  std::advance(historyCur, m_cmdHistory.size() - 1);
594 
595  buffer.clear();
596  curs_set(1);
597  }
598  else if (ch == KEY_RESIZE)
599  {
600  lineWidth = COLS - (sizeof("Oregon>") - 1);
601 
602  wresize(m_cmdOutput, 0xFFFF / COLS, COLS);
603 
604  ResizeWindow(cmdLine, 1, lineWidth, LINES - 1, (sizeof("Oregon>") - 1));
605  wmove(m_cmdOutput, LINES - 2, COLS - 1);
606 
607  werase(stdscr);
608 
609  pageSize = LINES - 4;
610  getmaxyx(m_cmdOutput, my, mx);
611  wmove(m_cmdOutput, my - 1, mx - 1);
612  waddch(m_cmdOutput, ' ');
613 
614  y = my - pageSize;
615 
616  update = true;
617  }
618 
619  }
620 
621  curs_set(0);
622  DestroyWindow(cmdLine);
623 }
624 
626 {
627  const char info[] = "Use arrows, PgUp/PgDn to scroll. Enter to return. (%lu%%)";
628  size_t len = sizeof(info) - 1;
629 
630  int y, mx, my;
631  int pageSize = LINES - 4;
632  getmaxyx(m_logViewer, my, mx);
633  my--;
634 
635  y = my - pageSize;
636 
637  Window* infoWindow = MakeWindow(2, len, LINES - 2, COLS / 2 - len / 2);
638  wattron(infoWindow, A_BOLD | TermColor(COLOR_GREEN));
639 
640  erase();
641  refresh();
642 
643  wrefresh(infoWindow);
644  timeout(1000);
645 
646  while (!World::IsStopped())
647  {
648  if (y == my - pageSize)
649  {
650  UpdateLog();
651  prefresh(m_logViewer, y, 0, 0, 0, pageSize + 1, COLS);
652  }
653  else
654  prefresh(m_logViewer, y, 0, 0, 0, pageSize, COLS);
655 
656  werase(infoWindow);
657  mvwprintw(infoWindow, 0, 0, info, (100 * y) / (my - pageSize));
658  wrefresh(infoWindow);
659 
660  int ch = GetChar();
661 
662  if (ch == KEY_ENTER || ch == '\r' || ch == '\n')
663  break;
664  else if (ch == KEY_PPAGE) // page up
665  y = std::max<int>(0, y - pageSize);
666  else if (ch == KEY_NPAGE) // page down
667  y = std::min<int>(my - pageSize, y + pageSize);
668  else if (ch == KEY_UP || ch == KEY_SR)
669  y = std::max<int>(0, y - 1);
670  else if (ch == KEY_DOWN || ch == KEY_SF)
671  y = std::min<int>(my - pageSize, y + 1);
672  else if (ch == KEY_RESIZE)
673  {
674  ResizeWindow(infoWindow, 2, len, LINES - 2, COLS / 2 - len / 2);
675 
676  wresize(m_logViewer, 0xFFFF / COLS, COLS);
677 
678  pageSize = LINES - 4;
679  getmaxyx(m_logViewer, my, mx);
680  wmove(m_logViewer, my - 1, mx - 1);
681  waddch(m_logViewer, ' ');
682 
683  y = my - pageSize;
684  }
685  }
686 
687  DestroyWindow(infoWindow);
688 }
689 
690 void Console::SetLoading(bool on, const char* caption)
691 {
692  if (!m_loadWindow || !m_IamEnabled)
693  return;
694 
695  if (on)
696  {
697  const char stop[] = "Press <CTRL-C> to stop";
698 
699  wattron(m_loadWindow, A_BOLD);
700 
701  wprintw(m_loadWindow, "%s ", caption);
702  mvwprintw(m_loadWindow, 0, sOregonLogoCols - (sizeof(stop) - 1), "%s", stop);
703 
704  wattroff(m_loadWindow, A_BOLD);
705  wrefresh(m_loadWindow);
706  }
707  else
708  {
710  m_loadWindow = NULL;
711  }
712 }
713 
714 void Console::SetLoadingLabel(const char* label, bool br)
715 {
716  if (m_IamEnabled)
717  {
718  if (!m_loadWindow)
719  return;
720 
721  wmove(m_loadWindow, 2, 0);
722  wclrtoeol(m_loadWindow);
723  mvwprintw(m_loadWindow, 2, 0, "%s", label);
724  wrefresh(m_loadWindow);
725  }
726  else
727  {
728  if (br)
729  sLog.outString();
730  sLog.outString("%s", label);
731  }
732 }
733 
734 void Console::FatalError(const char* msg)
735 {
737 
738  erase();
739 
740  Window* errWin = MakeWindow(LINES - (2 + sOregonLogoRows), sOregonLogoCols, 2 + sOregonLogoRows, COLS / 2 - sOregonLogoCols / 2);
741  wattrset(errWin, A_BOLD | TermColor(COLOR_RED));
742  wprintw(errWin, "FATAL ERROR:"
743  "\n\n"
744  "%s"
745  "\n\n"
746  "Press enter to exit", msg);
747  wrefresh(stdscr);
748  DrawLogo();
749  wrefresh(errWin);
750 
751  timeout(-1);
752  for (int c = GetChar(); (c != KEY_ENTER && c != '\n' && c != '\r'); c = GetChar())
753  ;
754 
755  DestroyWindow(errWin);
756 
757  endwin();
758 }
759 
761 {
762  static const char FavString[] = "Your Favourite TBC Server";
763 
764  if (m_IamEnabled)
765  {
766  werase(m_logoWindow);
767  scrollok(m_logoWindow, TRUE);
768  wattrset(m_logoWindow, A_BOLD | TermColor(COLOR_GREEN));
769  mvwprintw(m_logoWindow, 0, 0, "%s", sOregonLogo);
770  wattroff(m_logoWindow, TermColor(COLOR_GREEN));
771  wattron(m_logoWindow, TermColor(COLOR_CYAN));
772 
773  mvwprintw(m_logoWindow, 1, sOregonLogoCols / 2 - (sizeof(FavString) - 1) / 2, "%s", FavString);
774  mvwprintw(m_logoWindow, sOregonLogoRows - 1, 0, "%s", "http://www.oregon-core.net");
775 
776  wattroff(m_logoWindow, TermColor(COLOR_CYAN));
777  wrefresh(m_logoWindow);
778  }
779  else
780  {
781  sLog.outString();
782  for (uint32 i = 0; i < sOregonLogoRows; i++)
783  sLog.outString("%.*s", sOregonLogoCols, &sOregonLogo[i * sOregonLogoCols]);
784  sLog.outString("http://www.oregon-core.net\n");
785  }
786 }
787 
789 {
790  /* Before you start optimizing or "repairing" this functions bear in mind:
791  * we read from pipe (we try to read atomic chunks)
792  * read() calls are used in non-blocking I/O
793  * ReadFile() calls are used with PeekNamedPipe() to achieve non-blocking I/O
794  * read()/ReadFile() don't guarantee to read exactly *size* bytes
795  * we call this function to *free* bytes so logger can send another data
796 
797  So to properly handle colors we use our own special escapes:
798  * to apply a color we send 0xFF byte following with the color value
799  * to unapply color we send 0xFE byte
800  * 0xFF and 0xFE are chosen because they are invalid for utf8
801  * one call to this function may read 0xFF byte but not the actual color
802  so we use *static* control to check if the previous byte was 0xFF
803 
804  I admit this function is terrible for performance, although:
805  * it's run from separate thread (cliThread)
806  * user probably won't notice a delay
807  */
808 
809  static long control = 0;
810  unsigned char buffer[PIPE_BUF];
811 
812  #if PLATFORM == PLATFORM_WINDOWS
813  unsigned long len, i, total;
814  while (PeekNamedPipe(m_loggerFd, NULL, 0, NULL, &total, NULL) &&
815  total &&
816  ReadFile(m_loggerFd, buffer, std::min<unsigned long>(total, sizeof(buffer)), &len, NULL))
817  #else
818  ssize_t len, i;
819  while ((len = read(m_loggerFd, (char*)buffer, sizeof(buffer))) > 0)
820  #endif
821  {
822  for (i = 0; i < len; i++)
823  {
824  switch (buffer[i])
825  {
826  case 0xFF:
827  control = 1;
828  continue;
829  case 0xFE:
830  wattrset(m_logViewer, A_NORMAL);
831  continue;
832  default:
833  if (control)
834  {
835  control = 0;
836  if (buffer[i] > 7)
837  wattrset(m_logViewer, A_BOLD | TermColor(buffer[i] - 8));
838  else
839  wattrset(m_logViewer, TermColor(buffer[i]));
840  continue;
841  }
842 
843  waddch(m_logViewer, buffer[i]);
844  }
845  }
846  }
847 }
BOOL WINAPI HandleConsoleInterrupt(DWORD)
Definition: Console.cpp:49
#define dup2
Definition: Common.h:136
#define sConfig
Definition: Config.h:52
bool colored
Definition: Console.cpp:429
WINDOW Window
Definition: Console.h:9
void SetLoading(bool show, const char *caption="Initializing")
Definition: Console.cpp:690
#define sConsole
Definition: Console.h:99
History m_cmdHistory
Definition: Console.h:90
void DestroyWindow(Window *win)
Definition: Console.cpp:201
PipeType m_loggerFd
Definition: Console.h:91
#define sLog
Log class singleton.
Definition: Log.h:187
static bool IsStopped()
Definition: World.h:638
NULL Dbg ErrDB Arena Chat Char Map MMap false
Definition: Log.cpp:556
Window * m_logViewer
Definition: Console.h:95
Window * m_cmdOutput
Definition: Console.h:96
volatile long status
Definition: Console.cpp:428
void SetLoadingLabel(const char *label, bool br=true)
Definition: Console.cpp:714
#define SCROLLDN_MASK
Definition: Console.cpp:17
static void Sleep(unsigned long msecs)
Definition: Threading.cpp:237
Console()
Definition: Console.cpp:57
void SetTitle(const char *title)
Definition: Console.h:59
void RunLogViewLoop()
Definition: Console.cpp:625
#define SCROLLUP_MASK
Definition: Console.cpp:16
Window * MakeWindow(int h, int w, int y, int x)
Definition: Console.cpp:193
etc mysql my cnf *Then change max_allowed_packet to a bigger value
void MainLoop()
Definition: Console.cpp:243
Window * win
Definition: Console.cpp:427
void Initialize()
Definition: Console.cpp:86
int GetChar()
Definition: Console.cpp:218
#define TermColor(x)
Definition: Console.cpp:20
void FatalError(const char *msg)
Definition: Console.cpp:734
~Console()
Definition: Console.cpp:65
void Refresh()
Definition: Console.cpp:179
void ResizeWindow(Window *win, int h, int w, int y, int x)
Definition: Console.cpp:212
#define fileno
Definition: Common.h:135
void UpdateLog()
Definition: Console.cpp:788
Window * m_logoWindow
Definition: Console.h:93
#define ASSERT
Definition: Errors.h:33
#define sWorld
Definition: World.h:860
void RunCommandLoop()
Definition: Console.cpp:455
ACE_UINT32 uint32
Definition: Define.h:71
bool m_IamEnabled
Definition: Console.h:81
Window * m_loadWindow
Definition: Console.h:94
std::set< Window * > m_windows
Definition: Console.h:80
#define ticketmgr
Definition: TicketMgr.h:94
void Restore()
Definition: Console.cpp:187
INSTANTIATE_SINGLETON_1(Console)
void DrawLogo()
Definition: Console.cpp:760