• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2005, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #define _CRT_SECURE_NO_DEPRECATE 1
29 
30 #ifdef POSIX
31 #include <unistd.h>
32 #endif  // POSIX
33 #include <cassert>
34 #include "talk/base/logging.h"
35 #include "talk/base/messagequeue.h"
36 #include "talk/base/stringutils.h"
37 #include "talk/examples/call/console.h"
38 #include "talk/examples/call/callclient.h"
39 
40 #ifdef POSIX
41 #include <signal.h>
42 
DoNothing(int unused)43 static void DoNothing(int unused) {}
44 #endif
45 
Console(talk_base::Thread * thread,CallClient * client)46 Console::Console(talk_base::Thread *thread, CallClient *client) :
47   client_(client), client_thread_(thread),
48   console_thread_(new talk_base::Thread()), prompt_(std::string("call")),
49   prompting_(true) {
50 }
51 
~Console()52 Console::~Console() {
53   Stop();
54 }
55 
Start()56 void Console::Start() {
57   if (!console_thread_.get()) {
58     // stdin was closed in Stop(), so we can't restart.
59     LOG(LS_ERROR) << "Cannot re-start";
60     return;
61   }
62   if (console_thread_->started()) {
63     LOG(LS_WARNING) << "Already started";
64     return;
65   }
66   console_thread_->Start();
67   console_thread_->Post(this, MSG_START);
68 }
69 
Stop()70 void Console::Stop() {
71   if (console_thread_.get() && console_thread_->started()) {
72 #ifdef WIN32
73     CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
74 #else
75     close(fileno(stdin));
76     // This forces the read() in fgets() to return with errno = EINTR. fgets()
77     // will retry the read() and fail, thus returning.
78     pthread_kill(console_thread_->GetPThread(), SIGUSR1);
79 #endif
80     console_thread_->Stop();
81     console_thread_.reset();
82   }
83 }
84 
SetEcho(bool on)85 void Console::SetEcho(bool on) {
86 #ifdef WIN32
87   HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
88   if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL))
89     return;
90 
91   DWORD mode;
92   if (!GetConsoleMode(hIn, &mode))
93     return;
94 
95   if (on) {
96     mode = mode | ENABLE_ECHO_INPUT;
97   } else {
98     mode = mode & ~ENABLE_ECHO_INPUT;
99   }
100 
101   SetConsoleMode(hIn, mode);
102 #else
103   int re;
104   if (on)
105     re = system("stty echo");
106   else
107     re = system("stty -echo");
108   if (-1 == re)
109     return;
110 #endif
111 }
112 
Print(const char * str)113 void Console::Print(const char* str) {
114   printf("\n%s", str);
115   if (prompting_)
116     printf("\n(%s) ", prompt_.c_str());
117 }
118 
Print(const std::string & str)119 void Console::Print(const std::string& str) {
120   Print(str.c_str());
121 }
122 
Printf(const char * format,...)123 void Console::Printf(const char* format, ...) {
124   va_list ap;
125   va_start(ap, format);
126 
127   char buf[4096];
128   int size = vsnprintf(buf, sizeof(buf), format, ap);
129   assert(size >= 0);
130   assert(size < static_cast<int>(sizeof(buf)));
131   buf[size] = '\0';
132   Print(buf);
133 
134   va_end(ap);
135 }
136 
RunConsole()137 void Console::RunConsole() {
138   char input_buffer[128];
139   while (fgets(input_buffer, sizeof(input_buffer), stdin) != NULL) {
140     client_thread_->Post(this, MSG_INPUT,
141         new talk_base::TypedMessageData<std::string>(input_buffer));
142   }
143 }
144 
OnMessage(talk_base::Message * msg)145 void Console::OnMessage(talk_base::Message *msg) {
146   switch (msg->message_id) {
147     case MSG_START:
148 #ifdef POSIX
149       // Install a no-op signal so that we can abort RunConsole() by raising
150       // SIGUSR1.
151       struct sigaction act;
152       act.sa_handler = &DoNothing;
153       sigemptyset(&act.sa_mask);
154       act.sa_flags = 0;
155       if (sigaction(SIGUSR1, &act, NULL) < 0) {
156         LOG(LS_WARNING) << "Can't install signal";
157       }
158 #endif
159       RunConsole();
160       break;
161     case MSG_INPUT:
162       talk_base::TypedMessageData<std::string> *data =
163           static_cast<talk_base::TypedMessageData<std::string>*>(msg->pdata);
164       client_->ParseLine(data->data());
165       break;
166   }
167 }
168