From 78c07794bd9ed88d4a280140166a5909ad352f75 Mon Sep 17 00:00:00 2001
From: yanmorin <yanmorin>
Date: Tue, 20 Sep 2005 19:57:12 +0000
Subject: [PATCH] Only one socket now for reading/writing. Call and hangup
 almost working. EventThread now listening event. Simple ArgTokenizer (without
 urlDecode yet)

---
 src/eventthread.cpp                |   2 +-
 src/gui/official/test.cpp          |   2 +-
 src/gui/server/Makefile.am         |   2 +-
 src/gui/server/argtokenizer.h      |  71 ++---------------
 src/gui/server/guiserver.cpp       | 120 ++++++++++++++++-------------
 src/gui/server/guiserver.h         |  30 ++------
 src/gui/server/request.cpp         |  10 +++
 src/gui/server/request.h           |   8 +-
 src/gui/server/requestfactory.cpp  |   3 +
 src/gui/server/responsemessage.cpp |   6 +-
 src/gui/server/responsemessage.h   |   7 +-
 src/sipvoiplink.cpp                |   7 ++
 12 files changed, 119 insertions(+), 149 deletions(-)

diff --git a/src/eventthread.cpp b/src/eventthread.cpp
index 2caf0de457..fd25ed60e4 100644
--- a/src/eventthread.cpp
+++ b/src/eventthread.cpp
@@ -41,7 +41,7 @@ EventThread::~EventThread (void)
 void
 EventThread::run (void) 
 {
-  while(testCancel()) {
+  while(!testCancel()) {
     _sipthread->getEvent();
   }
 }
diff --git a/src/gui/official/test.cpp b/src/gui/official/test.cpp
index aa2ddf5e8b..93f145d183 100644
--- a/src/gui/official/test.cpp
+++ b/src/gui/official/test.cpp
@@ -6,7 +6,7 @@
 
 int main(int, char**)
 {
-  std::istringstream s(std::string("100 seq12 Maréponse \"sldkfjdfj s;dlfk\""));
+  std::istringstream s(std::string("100 seq12 Mar�onse \"sldk fjdfj\n\ns;d\tlfk\""));
   
   std::string output;
   std::list< std::string > args;
diff --git a/src/gui/server/Makefile.am b/src/gui/server/Makefile.am
index 7e523e574a..2e0203e2c0 100644
--- a/src/gui/server/Makefile.am
+++ b/src/gui/server/Makefile.am
@@ -1,7 +1,7 @@
 noinst_LTLIBRARIES = libsflphoneguiserver.la
 
 libsflphoneguiserver_la_SOURCES = $(BUILT_SOURCES) 	guiserver.cpp \
-		responsemessage.cpp request.cpp requestfactory.cpp
+			responsemessage.cpp request.cpp requestfactory.cpp argtokenizer.cpp
 
 libsflphoneguiserver_la_CXXFLAGS = -DPREFIX=\"$(prefix)\" -DPROGSHAREDIR=\"${datadir}/sflphone\"
 libsflphoneguiserver_la_LIBADD = 
diff --git a/src/gui/server/argtokenizer.h b/src/gui/server/argtokenizer.h
index 7042d7699a..3c19b7ecde 100644
--- a/src/gui/server/argtokenizer.h
+++ b/src/gui/server/argtokenizer.h
@@ -22,13 +22,12 @@
 
 #include <list>
 #include <string>
-#include <iostream>
 
 typedef std::list<std::string> TokenList;
 
 /**
 Separate a string into token
-a b "c d" = 3 tokens: [a], [b], [c d]
+a b c%20d = 3 tokens: [a], [b], [c d]
 
 Example:
 #include <argtokenizer.h>
@@ -45,68 +44,12 @@ public:
   ArgTokenizer() {}   //  ctor
   ~ArgTokenizer() {}  //  dtor
 
-  TokenList tokenize(const std::string& str)
-  {
-     TokenList stack; // token stack
-     std::string::size_type length = str.size();
-     std::string::size_type i, pos;
-     std::string temp;
-
-     bool inToken = false; // if we are inside a token or not
-     bool inQuote = false; // look if we are inside a "quoted-string"
-     char lastChar = '\0'; // lastChar for \" escaping inside quote
-     char c;
-
-     pos = 0; // position inside quoted string, to escape backslashed-doublequote
-     for (i=0;i<length;i++) {
-       c = str[i];
-       // for the new token
-       if (inToken == false) {
-         if (c == ' ') { continue; }   // escape space outside a token
-         else if (c == '"') {
-            inToken = true;
-            inQuote = true;
-            lastChar = '\0';
-            pos = 0;
-            continue;
-         } else {
-           inToken = true;
-         }
-       }
-       if (inToken) {
-       // we are inside a token
-         if (inQuote) { // we are looking for a " token
-           if ( c == '"' ) { 
-             if (lastChar == '\\') { 
-               temp[pos-1] = '"';
-             } else { // end of the string
-               if (temp.size()) { stack.push_back(temp); temp=""; }
-               temp = "";
-               inToken = false;
-               inQuote = false;
-             }
-           } else { // normal character to append
-             temp += c;
-             pos++;
-           }
-           lastChar = c;
-         } else { // not in quote, stop to first space
-           if ( c == ' ' ) {
-              if (temp.size()) { stack.push_back(temp); temp=""; }
-              inToken = false;
-           } else {
-             temp += c;
-           }
-         }
-       }
-     }
-     if (temp.size()) { stack.push_back(temp); } // add last keyword
-
-     return stack;
-  }
-
-  // look at http://yansanmo.no-ip.org/test/cpp/argtokenizer.h
-  // for test
+  /**
+   * Tokenize a string into a list of string
+   * Separators are: space, newline and tab ( ,\n,\t)
+   * @author: Jean-Philippe Barrette-LaPierre
+   */
+  TokenList tokenize(const std::string& str);
 };
 
 #endif // __ARG_TOKENIZER__
diff --git a/src/gui/server/guiserver.cpp b/src/gui/server/guiserver.cpp
index b6f63861e0..dab7006600 100644
--- a/src/gui/server/guiserver.cpp
+++ b/src/gui/server/guiserver.cpp
@@ -20,31 +20,27 @@
 #include "guiserver.h"
 #include <string>
 #include <iostream>
+#include <sstream>
+#include <stdexcept>
 #include "responsemessage.h"
 #include "request.h"
 
 void 
-TCPSessionReader::run() 
-{
+TCPSessionIO::run() {
   while(!testCancel() && good()) {
-    std::string output;
-    std::getline(*this, output);
-    _gui->pushRequestMessage(output);
-  }
-}
-
-void 
-TCPSessionWriter::run() 
-{
-  while (!testCancel() && good()) {
-   *this << _gui->popResponseMessage() << std::endl;
+    if (isPending(ost::TCPSocket::pendingInput)) {
+      std::string output;
+      std::getline(*this, output);
+      _gui->pushRequestMessage(output);
+    }
   }
 }
 
 // default constructor
 GUIServer::GUIServer()
 {
-  _factory.registerAll();}
+  _factory.registerAll();
+}
 
 // destructor
 GUIServer::~GUIServer()
@@ -70,16 +66,13 @@ GUIServer::exec() {
       std::cout << "waiting for a new connection..." << std::endl;
       
       //I'm accepting an incomming connection
-      sessionIn = new TCPSessionReader(aServer, this);
-      sessionOut = new TCPSessionWriter(aServer, this);
-      
-      sessionIn->start();
-      sessionOut->start();
+      _sessionIO   = new TCPSessionIO(aServer, this);
+      _sessionIO->start();
       
       // wait for the first message
       std::cout << "accepting connection..." << std::endl;
       
-      while(sessionIn->good() && sessionOut->good()) {
+      while(_sessionIO->good()) {
         request = popRequest();
         output = request->execute(*this);
         pushResponseMessage(output);
@@ -108,7 +101,7 @@ GUIServer::popRequest()
   Request *request = 0;
   while(!request) {
     _mutex.enterMutex();
-    if ( _requests.size() ) {
+    if ( _requests.begin() != _requests.end() ) {
       request = _requests.front();
       _requests.pop_front();
     }
@@ -122,7 +115,7 @@ GUIServer::pushResponseMessage(const ResponseMessage &response)
 {
   std::cout << "pushResponseMessage" << std::endl;
   _mutex.enterMutex();
-  _responses.push_back(response.toString());
+  *_sessionIO << response.toString() << std::endl;
   _mutex.leaveMutex();
 
   // remove the request from the list 
@@ -131,23 +124,6 @@ GUIServer::pushResponseMessage(const ResponseMessage &response)
   }
 }
 
-std::string 
-GUIServer::popResponseMessage() 
-{
-  bool canPop = false;
-  std::string message;
-  while(!canPop) {
-    _mutex.enterMutex();
-    if ( _responses.size() ) {
-      message = _responses.front();
-      _responses.pop_front();
-      canPop = true;
-    }
-    _mutex.leaveMutex();
-  }
-  return message;
-}
-
 /**
  * Remove a request with its sequence id
  */
@@ -177,6 +153,41 @@ GUIServer::removeSubCall(short id) {
   _callMap.erase(id);
 }
 
+/**
+ * Retreive the subcall or send 0
+ */
+std::string 
+GUIServer::getSequenceIdFromId(short id) {
+  CallMap::iterator iter = _callMap.find(id);
+  if (iter != _callMap.end()) {
+    return iter->second.sequenceId();
+  }
+  return "seq0";
+}
+
+short
+GUIServer::getIdFromCallId(const std::string& callId) 
+{
+  CallMap::iterator iter = _callMap.begin();
+  while (iter != _callMap.end()) {
+    if (iter->second.callId()==callId) {
+      return iter->first;
+    }
+  }
+  throw std::runtime_error("No match for this CallId");
+}
+
+void 
+GUIServer::hangup(const std::string& callId) {
+  try {
+    short id = getIdFromCallId(callId);
+    if (!GuiFramework::hangupCall(id)) {
+      throw std::runtime_error("Error when hangup");
+    }
+  } catch(...) {
+    throw;
+  }
+}
 
 int 
 GUIServer::incomingCall (short id) 
@@ -212,39 +223,44 @@ GUIServer::peerHungupCall (short id)
 void  
 GUIServer::displayTextMessage (short id, const std::string& message) 
 {
-  std::string responseMessage = "s";
-  responseMessage += id + " text message: " + message;
-  pushResponseMessage(ResponseMessage("700", "seq0", responseMessage));
+  std::ostringstream responseMessage;
+  std::string seq = getSequenceIdFromId(id);
+  responseMessage <<"s" << id << "text message: " + message;
+  pushResponseMessage(ResponseMessage("700", seq, responseMessage.str()));
 }
 
 void  
 GUIServer::displayErrorText (short id, const std::string& message) 
 {
-  std::string responseMessage = "s";
-  responseMessage += id + " error text: " + message;
-  pushResponseMessage(ResponseMessage("700", "seq0", responseMessage));
+  std::ostringstream responseMessage;
+  std::string seq = getSequenceIdFromId(id);
+  responseMessage << "s" << id << " error text: " << message;
+  pushResponseMessage(ResponseMessage("700", seq, responseMessage.str()));
 }
 
 void  
 GUIServer::displayError (const std::string& error) 
 {
-  std::string responseMessage = "error: " + error;
-  pushResponseMessage(ResponseMessage("700", "seq0", responseMessage));
+  std::ostringstream responseMessage;
+  responseMessage << "error: " << error;
+  pushResponseMessage(ResponseMessage("700", "seq0", responseMessage.str()));
 }
 
 void  
 GUIServer::displayStatus (const std::string& status) 
 {
-  std::string responseMessage = "status: " + status;
-  pushResponseMessage(ResponseMessage("700", "seq0", responseMessage));
+  std::ostringstream responseMessage;
+  responseMessage << "status: " + status;
+  pushResponseMessage(ResponseMessage("700", "seq0", responseMessage.str()));
 }
 
 void  
 GUIServer::displayContext (short id) 
 {
-  std::string responseMessage = "s";
-  responseMessage += id;
-  pushResponseMessage(ResponseMessage("700", "seq0", responseMessage));
+  std::ostringstream responseMessage;
+  responseMessage << "s" << id;
+  std::string seq = getSequenceIdFromId(id);
+  pushResponseMessage(ResponseMessage("700", seq, responseMessage.str()));
 }
 
 std::string  
diff --git a/src/gui/server/guiserver.h b/src/gui/server/guiserver.h
index 3f1981bce8..40b0a52abb 100644
--- a/src/gui/server/guiserver.h
+++ b/src/gui/server/guiserver.h
@@ -31,10 +31,10 @@
 #include "requestfactory.h"
 
 class GUIServer;
-class TCPSessionReader : public ost::TCPSession 
+class TCPSessionIO : public ost::TCPSession 
 {
 public:
-  TCPSessionReader(ost::TCPSocket &server, GUIServer *gui) : 
+  TCPSessionIO(ost::TCPSocket &server, GUIServer *gui) : 
     ost::TCPSession(server), 
     _gui(gui) {}
 
@@ -44,20 +44,6 @@ private:
   GUIServer *_gui;
 };
 
-class TCPSessionWriter : public ost::TCPSession 
-{
-public:
-  TCPSessionWriter(ost::TCPSocket &server, GUIServer *gui) : 
-    ost::TCPSession(server), 
-    _gui(gui) {}
-    
-  void run();
-    
-private:
-  GUIServer *_gui;
-};
-
-
 typedef std::map<short, SubCall> CallMap;
 class ResponseMessage;
 class GUIServer : public GuiFramework {
@@ -72,13 +58,13 @@ public:
   void pushRequestMessage(const std::string& request);
   Request *popRequest(void);
   void pushResponseMessage(const ResponseMessage& response);
-  std::string popResponseMessage(void);
   void removeRequest(const std::string& sequenceId);
 
   void insertSubCall(short id, SubCall& subCall);
   void removeSubCall(short id);
-  
-  
+  std::string getSequenceIdFromId(short id);
+  short getIdFromCallId(const std::string& callId);
+
   // Reimplementation of virtual functions
 	virtual int incomingCall (short id);
 	virtual void peerAnsweredCall (short id);
@@ -97,10 +83,11 @@ public:
 	virtual void stopVoiceMessageNotification (void);  
 
   int outgoingCall (const std::string& to) {return GuiFramework::outgoingCall(to);}
+  void hangup(const std::string& callId);
     
 private:
-  ost::TCPSession* sessionIn;
-  ost::TCPSession* sessionOut;
+  ost::TCPSession* _sessionIO;
+
   /**
    * This callMap is necessary because
    * ManagerImpl use callid-int
@@ -109,7 +96,6 @@ private:
    */
   CallMap _callMap;
   std::list<Request*> _requests;
-  std::list<std::string> _responses;
   RequestFactory _factory;
   ost::Mutex _mutex;
 };
diff --git a/src/gui/server/request.cpp b/src/gui/server/request.cpp
index 5bd675236d..91ccf32b21 100644
--- a/src/gui/server/request.cpp
+++ b/src/gui/server/request.cpp
@@ -34,4 +34,14 @@ RequestCall::execute(GUIServer& gui)
   }
 }
 
+ResponseMessage
+RequestHangup::execute(GUIServer& gui)
+{
+  try {
+    gui.hangup(_callId);
+    return message("200", "OK");
+  } catch (...) {
+    return message("500", "Hangup Error");
+  }
+}
 
diff --git a/src/gui/server/request.h b/src/gui/server/request.h
index 3701debcb9..c07a65cbdf 100644
--- a/src/gui/server/request.h
+++ b/src/gui/server/request.h
@@ -44,7 +44,7 @@ public:
   virtual ~Request() {}
   virtual ResponseMessage execute(GUIServer& gui) = 0;
   ResponseMessage message(const std::string &code, const std::string &message) {
-    ResponseMessage response(_sequenceId, code, message);
+    ResponseMessage response(code, _sequenceId, message);
     return response;
   }
   std::string sequenceId () const { return _sequenceId; }
@@ -131,7 +131,11 @@ class RequestTransfer : public RequestGlobalCall {
 public:
   RequestTransfer(const std::string &sequenceId, const TokenList& argList) : RequestGlobalCall(sequenceId,argList) {}
 };
-
+class RequestHangup : public RequestGlobalCall {
+public:
+  RequestHangup(const std::string &sequenceId, const TokenList& argList) : RequestGlobalCall(sequenceId,argList) {}
+  ResponseMessage execute(GUIServer& gui);
+};
 
 class RequestGlobal : public Request
 {
diff --git a/src/gui/server/requestfactory.cpp b/src/gui/server/requestfactory.cpp
index ae76e5c1fb..677049aa6d 100644
--- a/src/gui/server/requestfactory.cpp
+++ b/src/gui/server/requestfactory.cpp
@@ -28,11 +28,13 @@ RequestFactory::create(const std::string& requestLine)
   
   TokenList tList = _tokenizer.tokenize(requestLine);
   TokenList::iterator iter = tList.begin();
+
   // there is atleast one token (the command)
   if (iter != tList.end()) {
     std::string requestName = *iter;
     tList.pop_front();
     iter = tList.begin();
+
     // there is atleast a second token (the sequenceId)
     if (iter != tList.end() && iter->find("seq") == 0 ) {
       std::string sequenceId = *iter;
@@ -89,6 +91,7 @@ RequestFactory::registerAll() {
   registerRequest<RequestRefuse>   ("refuse");
   registerRequest<RequestHold>     ("hold");
   registerRequest<RequestUnhold>   ("unhold");
+  registerRequest<RequestHangup>   ("hangup");
   registerRequest<RequestTransfer> ("transfer");
   registerRequest<RequestMute>     ("mute");
   registerRequest<RequestUnmute>   ("unmute");
diff --git a/src/gui/server/responsemessage.cpp b/src/gui/server/responsemessage.cpp
index ce030455d2..46dc17d4c8 100644
--- a/src/gui/server/responsemessage.cpp
+++ b/src/gui/server/responsemessage.cpp
@@ -24,9 +24,9 @@
  */
 const std::string ResponseMessage::FINALCODE = "2456";
 
-ResponseMessage::ResponseMessage(const std::string& seq,
-      const std::string& code,
-      const std::string& message) : _seq(seq), _code(code), _message(message)
+ResponseMessage::ResponseMessage(const std::string& code,
+      const std::string& seq,
+      const std::string& message) : _code(code), _seq(seq), _message(message)
 {
 }
 
diff --git a/src/gui/server/responsemessage.h b/src/gui/server/responsemessage.h
index eae2c0c20e..2a2522ea9a 100644
--- a/src/gui/server/responsemessage.h
+++ b/src/gui/server/responsemessage.h
@@ -29,8 +29,9 @@ class ResponseMessage
 public:
     // default constructor with empty seq/code/message
     ResponseMessage() {}
-    ResponseMessage(const std::string& seq, const std::string& code,const std::string& message
-    );
+    // build a constructor with a TokenList
+    // so that they will be encoded..
+    ResponseMessage(const std::string& code,const std::string& seq, const std::string& message);
     ~ResponseMessage();
 
     std::string sequenceId() const { return _seq; }
@@ -39,8 +40,8 @@ public:
     bool isFinal() const;
 private:
     // 3 numbers long sequenceId
-    std::string _seq;
     std::string _code;
+    std::string _seq;
     std::string _message;
 
     static const std::string FINALCODE;
diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp
index cf317dd3ab..fb3cb8e0a1 100644
--- a/src/sipvoiplink.cpp
+++ b/src/sipvoiplink.cpp
@@ -547,6 +547,7 @@ SipVoIPLink::getEvent (void)
     return -1;
   }	
 
+  Manager::instance().displayErrorText(event->type, "getEvent");
   switch (event->type) {
     // IP-Phone user receives a new call
   case EXOSIP_CALL_INVITE: //
@@ -820,7 +821,13 @@ SipVoIPLink::getEvent (void)
     }
     break;
 
+  case EXOSIP_CALL_RELEASED:
+    //TODO: find the id...
+    Manager::instance().displayErrorText(0, "getEvent:CallReleased");
+
+    break;
   default:
+    Manager::instance().displayErrorText(event->type, "getEvent:default");
     return -1;
     break;
   }
-- 
GitLab