Logo
~Sockets~
~Examples~
~Contact~

InSocket.cpp

Go to the documentation of this file.
00001 // InSocket.cpp
00002 // released 2006-09-25
00003 /*
00004 Copyright (C) 2006  Anders Hedstrom (grymse@alhem.net)
00005 
00006 This program is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU General Public License
00008 as published by the Free Software Foundation; either version 2
00009 of the License, or (at your option) any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with this program; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 */
00020 #include <Parse.h>
00021 #include <arpa/telnet.h>
00022 #include <Utility.h>
00023 
00024 #include "InSocket.h"
00025 #include "cstring.h"
00026 #include "FutureHandler.h"
00027 #include "Login.h"
00028 #include "Player.h"
00029 #include "Command.h"
00030 
00031 #define  TELOPT_MXP        '\x5B'
00032 
00033 static  const unsigned char will_mxp_str  [] = { IAC, WILL, TELOPT_MXP, '\0' };
00034 static  const unsigned char start_mxp_str [] = { IAC, SB, TELOPT_MXP, IAC, SE, '\0' };
00035 static  const unsigned char do_mxp_str    [] = { IAC, DO, TELOPT_MXP, '\0' };
00036 static  const unsigned char dont_mxp_str  [] = { IAC, DONT, TELOPT_MXP, '\0' };
00037 
00038 
00039 InSocket::InSocket(ISocketHandler& h)
00040 :TcpSocket(h)
00041 ,IEventOwner(static_cast<FutureHandler&>(h))
00042 ,m_active_command(NULL)
00043 ,m_command_state(0)
00044 ,m_b_use_mxp(false)
00045 ,m_move_event(0)
00046 {
00047         SetLineProtocol();
00048 }
00049 
00050 
00051 InSocket::~InSocket()
00052 {
00053         printf("~InSocket()\n");
00054 }
00055 
00056 
00057 void InSocket::OnDelete()
00058 {
00059         Player pl(GetDatabase(), GetAccountName());
00060         static_cast<FutureHandler&>(Handler()).ClearEvents(this);
00061         if (pl.Exists())
00062         {
00063                 static_cast<FutureHandler&>(Handler()).GlobalEvent(this, pl.GetDisplayName() + " dropped.");
00064         }
00065 }
00066 
00067 
00068 void InSocket::OnAccept()
00069 {
00070         static_cast<FutureHandler&>(Handler()).Count("Number of connections");
00071         printf("%s\n", GetRemoteAddress().c_str());
00072         Send("&WWelcome &rto &gFuture&nMud.\n");
00073         write_to_buffer(will_mxp_str);
00074         SetPrompt(static_cast<FutureHandler&>(Handler()).GetLogin(), 0, "Name, please? ");
00075 }
00076 
00077 
00078 void InSocket::Send(const std::string& s)
00079 {
00080         cstring cs = s;
00081 //      TcpSocket::Send(cs.c_str());
00082         write_to_buffer(cs.c_str());
00083 }
00084 
00085 
00086 void InSocket::Sendf(char *format, ...)
00087 {
00088         va_list ap;
00089         va_start(ap, format);
00090         char slask[5000];
00091 #ifdef _WIN32
00092         vsprintf(slask, format, ap);
00093 #else
00094         vsnprintf(slask, 5000, format, ap);
00095 #endif
00096         va_end(ap);
00097         Send( slask );
00098 }
00099 
00100 
00101 void InSocket::SetPrompt(const std::string& p,bool colorize)
00102 {
00103         m_active_command = NULL;
00104         if (!p.size()) // default
00105         {
00106                 m_prompt = "> ";
00107         }
00108         else
00109         {
00110                 m_prompt = p;
00111         }
00112         m_colorize_prompt = colorize;
00113         SendPrompt();
00114 }
00115 
00116 
00117 void InSocket::SetPrompt(Command *cc,int state,const std::string& prompt,bool colorize)
00118 {
00119         m_active_command = cc;
00120         m_command_state = state;
00121         m_prompt = prompt;
00122         m_colorize_prompt = colorize;
00123         SendPrompt();
00124 }
00125 
00126 
00127 void InSocket::SendPrompt()
00128 {
00129         if (!m_colorize_prompt)
00130         {
00131                 write_to_buffer(m_prompt.c_str());
00132         }
00133         else
00134         {
00135                 Send(m_prompt);
00136         }
00137 }
00138 
00139 
00140 void InSocket::ReadLine()
00141 {
00142         if (ibuf.GetLength())
00143         {
00144                 size_t x = 0;
00145                 size_t n = ibuf.GetLength();
00146                 char tmp[TCP_BUFSIZE_READ + 1];
00147 
00148                 n = (n >= TCP_BUFSIZE_READ) ? TCP_BUFSIZE_READ : n;
00149                 ibuf.Read(tmp,n);
00150                 tmp[n] = 0;
00151 
00152                 for (size_t i = 0; i < n; i++)
00153                 {
00154                         unsigned char uc;
00155                         memcpy(&uc, &tmp[i], 1);
00156                         if (uc == IAC)
00157                         {
00158                                 size_t l = strlen((char *)do_mxp_str);
00159                                 if (!memcmp(tmp + i, do_mxp_str, l))
00160                                 {
00161                                         m_b_use_mxp = true;
00162                                         send_mxp_defines();
00163                                         memmove(tmp + i, tmp + i + l, strlen(tmp + i + l) + 1);
00164                                         n -= l;
00165                                 }
00166                                 else
00167                                 if (!memcmp(tmp + i, dont_mxp_str, strlen((char *)dont_mxp_str)))
00168                                 {
00169                                         m_b_use_mxp = false;
00170                                         l = strlen((char *)dont_mxp_str);
00171                                         memmove(tmp + i, tmp + i + l, strlen(tmp + i + l) + 1);
00172                                         n -= l;
00173                                 }
00174                         }
00175                         if (i >= n)
00176                                 break;
00177                         while (tmp[i] == 13 || tmp[i] == 10)
00178                         {
00179                                 char c = tmp[i];
00180                                 tmp[i] = 0;
00181                                 if (tmp[x])
00182                                 {
00183                                         m_line += (tmp + x);
00184                                 }
00185                                 OnLine( m_line );
00186                                 i++;
00187                                 if (i < n && (tmp[i] == 13 || tmp[i] == 10) && tmp[i] != c)
00188                                 {
00189                                         i++;
00190                                 }
00191                                 x = i;
00192                                 m_line = "";
00193                         }
00194                 }
00195                 if (tmp[x])
00196                 {
00197                         m_line += (tmp + x);
00198                 }
00199         }
00200 }
00201 
00202 
00203 void InSocket::OnLine(const std::string& line)
00204 {
00205         if (line[0] == ' ')
00206         {
00207                 size_t i = 0;
00208                 while (line[i] == ' ')
00209                         i++;
00210                 static_cast<FutureHandler&>(Handler()).Talk(this, line.substr(i));
00211                 SendPrompt();
00212                 return;
00213         }
00214         if (m_active_command)
00215         {
00216                 m_active_command -> OnLine(this, line, m_command_state);
00217                 return;
00218         }
00219         if (!line.size())
00220         {
00221                 SetPrompt();
00222                 return;
00223         }
00224         Parse pa(line);
00225         std::string cmd = pa.getword();
00226         static_cast<FutureHandler&>(Handler()).DoCommand(this, cmd, pa.getrest());
00227 }
00228 
00229 
00230 void InSocket::send_mxp_defines() // http://www.gammon.com.au/mushclient/addingservermxp.htm
00231 {
00232         write_to_buffer( start_mxp_str );
00233         write_to_buffer( MXPMODE (6) );  /* permanent secure mode */
00234         write_to_buffer( MXPTAG ("!-- Set up MXP elements --"));
00235         /* Exit tag */
00236         write_to_buffer( MXPTAG ("!ELEMENT Ex '<send>' FLAG=RoomExit"));
00237         /* Room description tag */
00238         write_to_buffer( MXPTAG ("!ELEMENT rdesc '<p>' FLAG=RoomDesc"));
00239         /* Get an item tag (for things on the ground) */
00240         write_to_buffer( MXPTAG 
00241                         ("!ELEMENT Get \"<send href='"
00242                                          "get &#39;&name;&#39;|"
00243                                          "examine &#39;&name;&#39;|"
00244                                          "drink &#39;&name;&#39;"
00245                          "' "
00246                          "hint='RH mouse click to use this object|"
00247                                          "Get &desc;|"
00248                                          "Examine &desc;|"
00249                                          "Drink from &desc;"
00250                          "'>\" ATT='name desc'") );
00251         /* Drop an item tag (for things in the inventory) */
00252         write_to_buffer( MXPTAG 
00253                         ("!ELEMENT Drop \"<send href='"
00254                                          "drop &#39;&name;&#39;|"
00255                                          "examine &#39;&name;&#39;|"
00256                                          "look in &#39;&name;&#39;|"
00257                                          "wear &#39;&name;&#39;|"
00258                                          "eat &#39;&name;&#39;|"
00259                                          "drink &#39;&name;&#39;"
00260                          "' "
00261                          "hint='RH mouse click to use this object|"
00262                                          "Drop &desc;|"
00263                                          "Examine &desc;|"
00264                                          "Look inside &desc;|"
00265                                          "Wear &desc;|"
00266                                          "Eat &desc;|"
00267                                          "Drink &desc;"
00268                          "'>\" ATT='name desc'") );
00269         /* Bid an item tag (for things in the auction) */
00270         write_to_buffer( MXPTAG 
00271                         ("!ELEMENT Bid \"<send href='bid &#39;&name;&#39;' "
00272                          "hint='Bid for &desc;'>\" "
00273                          "ATT='name desc'") );
00274         /* List an item tag (for things in a shop) */
00275         write_to_buffer( MXPTAG 
00276                         ("!ELEMENT List \"<send href='buy &#39;&name;&#39;' "
00277                          "hint='Buy &desc;'>\" "
00278                          "ATT='name desc'") );
00279         /* Player tag (for who lists, tells etc.) */
00280         write_to_buffer( MXPTAG 
00281                         ("!ELEMENT Player \"<send href='tell &#39;&name;&#39; ' "
00282                          "hint='Send a message to &name;' prompt>\" "
00283                          "ATT='name'") );
00284 }
00285 
00286 
00287 void InSocket::write_to_buffer(const char *s)
00288 {
00289         std::string tmp;
00290         size_t l = strlen(s);
00291         bool in_mxp = false; // MXP_BEGc ... MXP_ENDc
00292         bool in_ent = false; // MXP_AMPc ... ;
00293         for (size_t i = 0; i < l; i++)
00294         {
00295                 if (in_mxp)
00296                 {
00297                         if (s[i] == MXP_ENDc)
00298                         {
00299                                 if (m_b_use_mxp)
00300                                         tmp += '>';
00301                                 in_mxp = false;
00302                         }
00303                         else
00304                         {
00305                                 if (m_b_use_mxp)
00306                                         tmp += s[i];
00307                         }
00308                 }
00309                 else
00310                 if (in_ent)
00311                 {
00312                         if (m_b_use_mxp)
00313                                 tmp += s[i];
00314                         if (s[i] == ';')
00315                                 in_ent = false;
00316                 }
00317                 else
00318                 switch (s[i])
00319                 {
00320                 case MXP_BEGc:
00321                         if (m_b_use_mxp)
00322                                 tmp += '<';
00323                         in_mxp = true;
00324                         break;
00325                 case MXP_AMPc:
00326                         if (m_b_use_mxp)
00327                                 tmp += '&';
00328                         in_ent = true;
00329                         break;
00330                 case MXP_ENDc: // huh
00331                         break;
00332                 case '<':
00333                         if (m_b_use_mxp)
00334                                 tmp += "&lt;";
00335                         else
00336                                 tmp += s[i];
00337                         break;
00338                 case '>':
00339                         if (m_b_use_mxp)
00340                                 tmp += "&gt;";
00341                         else
00342                                 tmp += s[i];
00343                         break;
00344                 case '&':
00345                         if (m_b_use_mxp)
00346                                 tmp += "&amp;";
00347                         else
00348                                 tmp += s[i];
00349                         break;
00350                 case '"':
00351                         if (m_b_use_mxp)
00352                                 tmp += "&quot;";
00353                         else
00354                                 tmp += s[i];
00355                         break;
00356                 default:
00357                         tmp += s[i];
00358                 }
00359         }
00360         TcpSocket::Send(tmp);
00361 }
00362 
00363 
00364 void InSocket::write_to_buffer(const unsigned char *s)
00365 {
00366         SendBuf((const char *)s, strlen((char *)s));
00367 }
00368 
00369 
00370 Database& InSocket::GetDatabase()
00371 {
00372         return static_cast<FutureHandler&>(Handler()).GetDatabase();
00373 }
00374 
00375 
00376 void InSocket::OnEvent(int id)
00377 {
00378         if (id == m_move_event)
00379         {
00380                 m_move_event = 0;
00381                 if (m_move_buffer.size())
00382                 {
00383                         std::list<std::string>::iterator it = m_move_buffer.begin();
00384                         std::string move = *it;
00385                         m_move_buffer.erase(it);
00386                         Command *cc = NULL;
00387                         if (move == "forward")
00388                                 cc = static_cast<FutureHandler&>(Handler()).GetCommand("forward");
00389                         else
00390                         if (move == "enter")
00391                                 cc = static_cast<FutureHandler&>(Handler()).GetCommand("enter");
00392                         else
00393                         switch (move[0])
00394                         {
00395                         case 'n':
00396                                 cc = static_cast<FutureHandler&>(Handler()).GetCommand("north");
00397                                 break;
00398                         case 's':
00399                                 cc = static_cast<FutureHandler&>(Handler()).GetCommand("south");
00400                                 break;
00401                         case 'e':
00402                                 cc = static_cast<FutureHandler&>(Handler()).GetCommand("east");
00403                                 break;
00404                         case 'w':
00405                                 cc = static_cast<FutureHandler&>(Handler()).GetCommand("west");
00406                                 break;
00407                         case 'u':
00408                                 cc = static_cast<FutureHandler&>(Handler()).GetCommand("up");
00409                                 break;
00410                         case 'd':
00411                                 cc = static_cast<FutureHandler&>(Handler()).GetCommand("down");
00412                                 break;
00413                         }
00414                         if (cc)
00415                         {
00416                                 std::string tmp = "nomap";
00417                                 Parse pa(tmp);
00418                                 if (move == "forward")
00419                                 {
00420                                         Send("\nMoving forward\n");
00421                                 }
00422                                 else
00423                                 if (move == "enter")
00424                                 {
00425                                         Send("\nEntering portal...\n");
00426                                 }
00427                                 else
00428                                 {
00429                                         Send("\nMoving " + cc -> GetCommand() + "\n");
00430                                 }
00431                                 cc -> Execute(this, tmp, pa);
00432                         }
00433                 }
00434         }
00435         else
00436         {
00437                 Send("\nEvent: " + Utility::l2string(id) + "\n");
00438                 SendPrompt();
00439         }
00440 }
00441 
00442 
00443 int InSocket::AddEvent(long sec,long usec)
00444 {
00445         return static_cast<FutureHandler&>(Handler()).AddEvent(this, sec, usec);
00446 }
00447 
00448 
00449 void InSocket::BufferMove(const std::string& x)
00450 {
00451         m_move_buffer.push_back(x);
00452         Send("Buffering move.\n");
00453         SetPrompt();
00454 }
00455 
00456 
00457 void InSocket::SetMoveEvent(long sec,long usec)
00458 {
00459         m_move_event = AddEvent(sec, usec);
00460 }
00461 
00462 
00463 void InSocket::CancelMoves()
00464 {
00465         while (m_move_buffer.size())
00466         {
00467                 std::list<std::string>::iterator it = m_move_buffer.begin();
00468                 m_move_buffer.erase(it);
00469         }
00470 }
00471 
00472 
00473 void InSocket::GlobalEvent(const std::string& x)
00474 {
00475         static_cast<FutureHandler&>(Handler()).GlobalEvent(this, x);
00476 }
00477 
00478 
00479 void InSocket::Count(const std::string& x)
00480 {
00481         static_cast<FutureHandler&>(Handler()).Count(x);
00482 }
00483 
00484 
Page, code, and content Copyright (C) 2006 by Anders Hedström
Generated on Mon Aug 29 20:21:47 2005 for C++ Sockets by  doxygen 1.4.4