Home | History | Annotate | Download | only in call
      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 
     43 static void DoNothing(int unused) {}
     44 #endif
     45 
     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 
     52 Console::~Console() {
     53   Stop();
     54 }
     55 
     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 
     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 
     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 
    113 void Console::Print(const char* str) {
    114   printf("\n%s", str);
    115   if (prompting_)
    116     printf("\n(%s) ", prompt_.c_str());
    117 }
    118 
    119 void Console::Print(const std::string& str) {
    120   Print(str.c_str());
    121 }
    122 
    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 
    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 
    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