Esempio n. 1
0
File: sycls.c Progetto: erluko/socat
int Recvmsg(int s, struct msghdr *msgh, int flags) {
   int retval, _errno;
   char infobuff[256];
#if defined(HAVE_STRUCT_MSGHDR_MSGCONTROL) && defined(HAVE_STRUCT_MSGHDR_MSGCONTROLLEN) && defined(HAVE_STRUCT_MSGHDR_MSGFLAGS)
   Debug10("recvmsg(%d, %p{%p,%u,%p,%u,%p,%u,%d}, %d)", s, msgh,
	  msgh->msg_name, msgh->msg_namelen,  msgh->msg_iov,  msgh->msg_iovlen,
	  msgh->msg_control,  msgh->msg_controllen,  msgh->msg_flags, flags);
#else
   Debug7("recvmsg(%d, %p{%p,%u,%p,%u}, %d)", s, msgh,
	  msgh->msg_name, msgh->msg_namelen,  msgh->msg_iov,  msgh->msg_iovlen,
	  flags);
#endif
   retval = recvmsg(s, msgh, flags);
   _errno = errno;
#if defined(HAVE_STRUCT_MSGHDR_MSGCONTROLLEN)
   Debug5("recvmsg(, {%s,%u,,%u,,%u,}, ) -> %d",
	  msgh->msg_name?sockaddr_info(msgh->msg_name, msgh->msg_namelen, infobuff, sizeof(infobuff)):"NULL",
	  msgh->msg_namelen, msgh->msg_iovlen, msgh->msg_controllen,
	  retval);
#else
   Debug4("recvmsg(, {%s,%u,,%u,,}, ) -> %d",
	  msgh->msg_name?sockaddr_info(msgh->msg_name, msgh->msg_namelen, infobuff, sizeof(infobuff)):"NULL",
	  msgh->msg_namelen, msgh->msg_iovlen,
	  retval);
#endif
   errno = _errno;
   return retval;
}
Esempio n. 2
0
File: sycls.c Progetto: erluko/socat
int Gettimeofday(struct timeval *tv, struct timezone *tz) {
   int result, _errno;
#if WITH_MSGLEVEL <= E_DEBUG
   if (tz) {
      Debug3("gettimeofday(%p, {%d,%d})",
	     tv, tz->tz_minuteswest, tz->tz_dsttime);
   } else {
      Debug1("gettimeofday(%p, NULL)", tv);
   }
#endif /* WITH_MSGLEVEL <= E_DEBUG */
   result = gettimeofday(tv, tz);
   _errno = errno;
#if WITH_MSGLEVEL <= E_DEBUG
   if (tz) {
      Debug5("gettimeofday({%ld,%ld}, {%d,%d}) -> %d",
             tv->tv_sec, tv->tv_usec, tz->tz_minuteswest, tz->tz_dsttime,
	     result);
   } else {
      Debug3("gettimeofday({%ld,%ld},) -> %d",
	     tv->tv_sec, tv->tv_usec, result);
   }
#endif /* WITH_MSGLEVEL <= E_DEBUG */
   errno = _errno;
   return result;
}
Esempio n. 3
0
File: sycls.c Progetto: erluko/socat
int Send(int s, const void *mesg, size_t len, int flags) {
   int retval, _errno;
   Debug5("send(%d, %p[%08x...], "F_Zu", %d)",
	  s, mesg, ntohl(*(unsigned long *)mesg), len, flags);
   retval = send(s, mesg, len, flags);
   _errno = errno;
   Debug1("send() -> %d", retval);
   errno = _errno;
   return retval;
}
Esempio n. 4
0
File: sycls.c Progetto: erluko/socat
int Getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) {
   int result, _errno;
   Debug5("getsockopt(%d, %d, %d, %p, {"F_Zd"})",
	  s, level, optname, optval, *optlen);
   result = getsockopt(s, level, optname, optval, optlen);
   _errno = errno;
   Debug3("getsockopt() -> (,,, 0x%08x, %d), %d",
	  *(int *)optval, *optlen, result);
   errno = _errno;
   return result;
}
Esempio n. 5
0
File: sycls.c Progetto: erluko/socat
int Openpty(int *ptyfd, int *ttyfd, char *ptyname, struct termios *termp,
	    struct winsize *winp) {
   int result, _errno;
   Debug5("openpty(%p, %p, %p, %p, %p)", ptyfd, ttyfd, ptyname, termp, winp);
   result = openpty(ptyfd, ttyfd, ptyname, termp, winp);
   _errno = errno;
   Info4("openpty({%d}, {%d}, {\"%s\"},,) -> %d", *ptyfd, *ttyfd, ptyname,
	  result);
   errno = _errno;
   return result;
}
Esempio n. 6
0
File: sycls.c Progetto: erluko/socat
int Uname(struct utsname *buf) {
   int result, _errno;
   Debug1("uname(%p)", buf);
   result = uname(buf);
   _errno = errno;
#if UNAME_DOMAINNAME
   Debug6("uname({%s, %s, %s, %s, %s, %s})",
	  buf->sysname, buf->nodename, buf->release,
	  buf->version, buf->machine, buf->domainname);
#else
   Debug5("uname({%s, %s, %s, %s, %s})",
	  buf->sysname, buf->nodename, buf->release,
	  buf->version, buf->machine);
#endif
   errno = _errno;
   return result;
}
Esempio n. 7
0
File: sycls.c Progetto: erluko/socat
int Setsockopt(int s, int level, int optname, const void *optval, int optlen) {
   int result, _errno;
   if (optlen <= sizeof(int)) {
      Debug5("setsockopt(%d, %d, %d, {0x%x}, %d)",
       s, level, optname, *(unsigned int *)optval, optlen);
   } else {
      Debug6("setsockopt(%d, %d, %d, {0x%08x,%08x}, %d)",
	     s, level, optname,
	     ((unsigned int *)optval)[0], ((unsigned int *)optval)[1],
	     optlen);
   }
   result = setsockopt(s, level, optname, optval, optlen);
   _errno = errno;
   Debug1("setsockopt() -> %d", result);
   errno = _errno;
   return result;
}
Esempio n. 8
0
File: sycls.c Progetto: erluko/socat
/* we only show the first struct pollfd; hope this is enough for most cases. */
int Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
   int result;
   if (nfds == 4) {
      Debug10("poll({%d,0x%02hx,}{%d,0x%02hx,}{%d,0x%02hx,}{%d,0x%02hx,}, %u, %d)",
	      ufds[0].fd, ufds[0].events, ufds[1].fd, ufds[1].events,
	      ufds[2].fd, ufds[2].events, ufds[3].fd, ufds[3].events,
	      nfds, timeout);
   } else {
      Debug4("poll({%d,0x%02hx,}, , %u, %d)", ufds[0].fd, ufds[0].events, nfds, timeout);
   }
   result = poll(ufds, nfds, timeout);
   if (nfds == 4) {
      Debug5("poll(, {,,0x%02hx}{,,0x%02hx}{,,0x%02hx}{,,0x%02hx}) -> %d",
	     ufds[0].revents, ufds[1].revents, ufds[2].revents, ufds[3].revents, result);
   } else {
      Debug2("poll(, {,,0x%02hx}) -> %d", ufds[0].revents, result);
   }
   return result;
}
Esempio n. 9
0
File: sycls.c Progetto: erluko/socat
int Execvp(const char *file, char *const argv[]) {
   int result, _errno;
   if (argv[1] == NULL)
      Debug2("execvp(\"%s\", \"%s\")", file, argv[0]);
   else if (argv[2] == NULL)
      Debug3("execvp(\"%s\", \"%s\" \"%s\")", file, argv[0], argv[1]);
   else if (argv[3] == NULL)
      Debug4("execvp(\"%s\", \"%s\" \"%s\" \"%s\")", file, argv[0], argv[1], argv[2]);
   else if (argv[4] == NULL)
      Debug5("execvp(\"%s\", \"%s\" \"%s\" \"%s\" \"%s\")", file, argv[0], argv[1], argv[2], argv[3]);
   else if (argv[5] == NULL)
      Debug6("execvp(\"%s\", \"%s\" \"%s\" \"%s\" \"%s\" \"%s\")", file, argv[0], argv[1], argv[2], argv[3], argv[4]);
   else
      Debug6("execvp(\"%s\", \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" ...)", file, argv[0], argv[1], argv[2], argv[3], argv[4]);

   result = execvp(file, argv);
   _errno = errno;
   Debug1("execvp() -> %d", result);
   errno = _errno;
   return result;
}
Esempio n. 10
0
bool PaladinJr::SpeedCheck(Client* client, gemActor* actor, psDRMessage& currUpdate)
{
    csVector3 oldpos;
    // Dummy variables
    float yrot;
    iSector* sector;
    psWorld * world = entitymanager->GetWorld();
    int violation = NOVIOLATION;

    actor->pcmove->GetLastClientPosition (oldpos, yrot, sector);
    
    // If no previous observations then we have nothing to check against.
    if (!sector)
        return true;

    // define cheating variables
    float dist;
    float reported_distance;
    float max_noncheat_distance;
    float lag_distance;
    csTicks timedelta;
    csVector3 vel;

    // check for warpviolation
    if (sector != currUpdate.sector && !world->WarpSpace(sector, currUpdate.sector, oldpos))
    {
        if (checks & WARPVIOLATION)
        {
            violation = WARPVIOLATION;
        }
        else
        {
            // we don't do warp checking and crossed a sector
            // skip this round
            return true;
        }
    }

    if (checks & SPEEDVIOLATION)
    {
        // we don't use the absolute value of the vertical
        // speed in order to let falls go through
        if (fabs(currUpdate.vel.x) <= maxVelocity.x &&
                 currUpdate.vel.y  <= maxVelocity.y &&
            fabs(currUpdate.vel.z) <= maxVelocity.z)
        {
            violation |= SPEEDVIOLATION;
        }
    }

    // distance check is skipped on warp violation as it would be wrong
    if (checks & DISTVIOLATION && !(violation & WARPVIOLATION))
    {
        dist = (currUpdate.pos-oldpos).Norm();
        timedelta = actor->pcmove->ClientTimeDiff();

        // We use the last reported vel, not the new vel, to calculate how far he should have gone since the last DR update
        vel = actor->pcmove->GetVelocity();
        vel.y = 0; // ignore vertical velocity
        reported_distance = vel.Norm()*timedelta/1000;

        Debug4(LOG_CHEAT, client->GetClientNum(),"Player went %1.3fm in %u ticks when %1.3fm was allowed.\n",dist, timedelta, reported_distance);

        max_noncheat_distance = maxSpeed*timedelta/1000;
        lag_distance          = maxSpeed*client->accumulatedLag/1000;

        if (dist < max_noncheat_distance + lag_distance)
        {
            if(dist == 0)
            {
                // player is stationary - reset accumulated lag
                NetBase::Connection * connection = client->GetConnection();
                client->accumulatedLag = connection->estRTT + connection->devRTT;
            }
            else if(fabs(dist-reported_distance) < dist/20)
            {
                // ignore jitter caused differences
                Debug1(LOG_CHEAT, client->GetClientNum(),"Ignoring lag jitter.");
            }
            else
            {
                // adjust accumulated lag
                float lag = (reported_distance - dist) * 1000.f/maxSpeed + client->accumulatedLag;

                // cap to meaningful values
                lag = lag < 0 ? 0 : lag > MAX_ACCUMULATED_LAG ? MAX_ACCUMULATED_LAG : lag;

                client->accumulatedLag = (csTicks)lag;

                Debug2(LOG_CHEAT, client->GetClientNum(),"Accumulated lag: %u\n",client->accumulatedLag);
            }
        }
        else
        {
            violation |= DISTVIOLATION;
        }
    }

    if (violation != NOVIOLATION)
    {
        if (client->GetCheatMask(MOVE_CHEAT))
        {
            //printf("Server has pre-authorized this apparent speed violation.\n");
            client->SetCheatMask(MOVE_CHEAT, false);  // now clear the Get Out of Jail Free card
            return true;  // not cheating
        }

        Debug6(LOG_CHEAT, client->GetClientNum(),"Went %1.2f in %u ticks when %1.2f was expected plus %1.2f allowed lag distance (%1.2f)\n", dist, timedelta, max_noncheat_distance, lag_distance, max_noncheat_distance+lag_distance);
        //printf("Z Vel is %1.2f\n", currUpdate.vel.z);
        //printf("MaxSpeed is %1.2f\n", maxSpeed);

        // Report cheater
        csVector3 angVel;
        csString buf;
        csString type;
        csString sectorName(sector->QueryObject()->GetName());

        // Player has probably been warped
        if (violation & WARPVIOLATION)
        {
            sectorName.Append(" to ");
            sectorName.Append(currUpdate.sectorName);
            type = "Warp Violation";
        }

        if (violation & SPEEDVIOLATION)
        {
            if(!type.IsEmpty())
                type += "|";
            type += "Speed Violation (Hack confirmed)";
        }

        if (violation & DISTVIOLATION)
        {
            if(!type.IsEmpty())
                type += "|";
            type += "Distance Violation";
        }

        if (enforcing)
        {
            actor->ForcePositionUpdate();
        }
        
        actor->pcmove->GetAngularVelocity(angVel);
        buf.Format("%s, %s, %s, %.3f %.3f %.3f, %.3f 0 %.3f, %.3f %.3f %.3f, %.3f %.3f %.3f, %.3f %.3f %.3f, %s\n",
                   client->GetName(), type.GetData(), sectorName.GetData(),oldpos.x, oldpos.y, oldpos.z,
                   max_noncheat_distance, max_noncheat_distance, 
                   currUpdate.pos.x - oldpos.x, currUpdate.pos.y - oldpos.y, currUpdate.pos.z - oldpos.z,
                   vel.x, vel.y, vel.z, angVel.x, angVel.y, angVel.z, PALADIN_VERSION);

        psserver->GetLogCSV()->Write(CSV_PALADIN, buf);

        Debug5(LOG_CHEAT, client->GetClientNum(),"Player %s traversed %1.2fm in %u msec with an accumulated lag allowance of %u ms. Cheat detected!\n",
            client->GetName (),dist,timedelta,client->accumulatedLag);

        client->CountDetectedCheat();
        //printf("Client has %d detected cheats now.\n", client->GetDetectedCheatCount());
        if (client->GetDetectedCheatCount() % warnCount == 0)
        {
            psserver->SendSystemError(client->GetClientNum(),"You have been flagged as using speed hacks.  You will be disconnected if you continue.");
        }
        if (client->GetDetectedCheatCount() >= maxCount)
        {
            //printf("Disconnecting a cheating client.\n");
            psserver->RemovePlayer(client->GetClientNum(),"Paladin has kicked you from the server for cheating.");
            return false;
        }

        return !enforcing;
    }
    else
    {
        return true;
    }
}
Esempio n. 11
0
bool NetBase::CheckIn()
{    
    // check for incoming packets
    SOCKADDR_IN addr;
    memset (&addr, 0, sizeof(SOCKADDR_IN));
    socklen_t len = sizeof(SOCKADDR_IN);

    if (!input_buffer)
    {
        input_buffer = (char*) cs_malloc(MAXPACKETSIZE);

        if (!input_buffer)
        {
            Error2("Failed to cs_malloc %d bytes for packet buffer!\n",MAXPACKETSIZE);
            return false;
        }
    }

    // Connection must be initialized!
    CS_ASSERT(ready);
    
    int packetlen = RecvFrom (&addr, &len, (void*) input_buffer, MAXPACKETSIZE);

    if (packetlen <= 0)
    {
        return false;
    }
    // Identify the connection
    Connection* connection = GetConnByIP(&addr);

    // Extract the netpacket from the buffer and prep for use locally.
    psNetPacket *bufpacket = psNetPacket::NetPacketFromBuffer(input_buffer,packetlen);
    if (bufpacket==NULL)
    {
        char addrText[INET_ADDRSTRLEN];

        //for win32 for now only inet_ntoa as inet_ntop wasn't supported till vista.
        //it has the same degree of compatibility of the previous code and it's supported till win2000
        #ifdef WIN32
        strncpy(addrText, inet_ntoa(addr.sin_addr), INET_ADDRSTRLEN);
        #else
        //there was a failure in conversion if null
        if(!inet_ntop(addr.sin_family,&addr.sin_addr, addrText, sizeof(addrText)))
        {
            strncpy(addrText, "UNKNOWN", INET_ADDRSTRLEN);
        }
        #endif

        // The data received was too small to make a full packet.
        if (connection)
        {
            Debug4(LOG_NET, connection->clientnum, "Too short packet received from client %d (IP: %s) (%d bytes)", connection->clientnum, addrText, packetlen);
        }
        else
        {
            Debug3(LOG_NET, 0, "Too short packet received from IP address %s. (%d bytes) No existing connection from this IP.",
                addrText, packetlen);
        }
        return true; // Continue processing more packets if available
    }
    input_buffer = NULL; //input_buffer now hold by the bufpacket pointer.

    // Endian correction
    bufpacket->UnmarshallEndian();

    // Check for too-big packets - no harm in processing them, but probably a bug somewhere
    if (bufpacket->GetPacketSize() < static_cast<unsigned int>(packetlen))
    {
        char addrText[INET_ADDRSTRLEN];

        //for win32 for now only inet_ntoa as inet_ntop wasn't supported till vista.
        //it has the same degree of compatibility of the previous code and it's supported till win2000
        #ifdef WIN32
        strncpy(addrText, inet_ntoa(addr.sin_addr), INET_ADDRSTRLEN);
        #else
        //there was a failure in conversion if null
        if(!inet_ntop(addr.sin_family,&addr.sin_addr, addrText, sizeof(addrText)))
        {
            strncpy(addrText, "UNKNOWN", INET_ADDRSTRLEN);
        }
        #endif
        
        if (connection)
        {
            Debug5(LOG_NET, connection->clientnum, "Too long packet received from client %d (IP: %s) (%d bytes received, header reports %zu bytes)",
                connection->clientnum, addrText, packetlen, bufpacket->GetPacketSize());
        }
        else
        {
            
            Debug4(LOG_NET, 0,"Too long packet received from IP address %s. (%d bytes received, header reports %zu bytes) No existing connection from this IP.",
                   addrText, packetlen, bufpacket->GetPacketSize());
        }
    }

    //Create new net packet entry and transfer ownership of bufpacket to pkt.
    csRef<psNetPacketEntry> pkt;
    pkt.AttachNew(new psNetPacketEntry( bufpacket, 
            connection ? connection->clientnum : 0, packetlen));
    
    if(TEST_PACKETLOSS > 0.0 && randomgen->Get() < TEST_PACKETLOSS)
    {
        psNetPacket* packet = pkt->packet;
        int type = 0;

        if (packet->offset == 0) 
        {
            psMessageBytes* msg = (psMessageBytes*) packet->data;
            type = msg->type;
        }

        Error3("Packet simulated lost. Type %s ID %d.\n", type == 0 ? "Fragment" : (const char *)  GetMsgTypeName(type), pkt->packet->pktid);
        return true;
    }

    // ACK packets can get eaten by HandleAck
    if (HandleAck(pkt, connection, &addr))
    {
        return true;
    }

    // printf("Got packet with sequence %d.\n", pkt->packet->GetSequence());
    //
    // Check for doubled packets and drop them
    if (pkt->packet->pktid != 0)
    {
        if (connection && CheckDoublePackets (connection, pkt))
        {
#ifdef PACKETDEBUG
            Debug2(LOG_NET,0,"Dropping doubled packet (ID %d)\n", pkt->packet->pktid);
#endif
            return true;
        }
    }
    
#ifdef PACKETDEBUG
    Debug7(LOG_NET,0,"Received Pkt, ID: %d, offset %d, from %d size %d (actual %d) flags %d\n", 
        pkt->packet->pktid, pkt->packet->offset, pkt->clientnum, pkt->packet->pktsize,packetlen, pkt->packet->flags);
#endif

    /**
    * Now either send this packet to BuildMessage, or loop through
    * subpackets if they are merged.
    */
    csRef<psNetPacketEntry> splitpacket = pkt;
    psNetPacket      *packetdata = NULL;

    do
    {
        splitpacket = pkt->GetNextPacket(packetdata);
        if (splitpacket)
            BuildMessage(splitpacket, connection, &addr);
    } while (packetdata);
    return true;
}
Esempio n. 12
0
void ChatManager::HandleChatMessage(MsgEntry *me, Client *client)
{
    psChatMessage msg(me);

    // Dont
    if (!msg.valid)
    {
        Debug2(LOG_NET,me->clientnum,"Received unparsable psChatMessage from client %u.\n",me->clientnum);
        return;
    }

    const char *pType = msg.GetTypeText();

    if (msg.iChatType != CHAT_TELL && msg.iChatType != CHAT_AWAY)
    {
        Debug4(LOG_CHAT, client->GetClientNum(),
                "%s %s: %s\n", client->GetName(),
                pType, msg.sText.GetData());
    }
    else
    {
        Debug5(LOG_CHAT,client->GetClientNum(), "%s %s %s: %s\n", client->GetName(),
               pType, msg.sPerson.GetData(),msg.sText.GetData());
    }

    bool saveFlood = true;

    if (!client->IsMute())
    {
      // Send Chat to other players
      switch (msg.iChatType)
      {
          case CHAT_GUILD:
          {
              SendGuild(client, msg);
              break;
          }
          case CHAT_ALLIANCE:
          {
              SendAlliance(client, msg);
              break;
          }
          case CHAT_GROUP:
          {
              SendGroup(client, msg);
              break;
           }
          case CHAT_AUCTION:
          case CHAT_SHOUT:
          {
              SendShout(client, msg);
              break;
          }
          case CHAT_CHANNEL:
          {
              csArray<uint32_t> subscribed = channelSubscriptions.GetAll(client->GetClientNum());
              bool found = false;
              for(size_t i = 0; i < subscribed.GetSize(); i++)
              {
                  if(subscribed[i] == msg.channelID)
                      found = true;
              }
              if(!found)
              {
                  psserver->SendSystemError(client->GetClientNum(), "You have not yet joined this channel.");
                  break;
              }

              // channel 1 is public
              if(msg.channelID == 1)
                  CPrintf (CON_WARNING, "Gossip %s: %s\n", client->GetName(), msg.sText.GetData());

              psChatMessage newMsg(client->GetClientNum(), client->GetActor()->GetEID(), client->GetName(), 0, msg.sText, msg.iChatType, msg.translate, msg.channelID);

              csArray<uint32_t> subscribers = channelSubscribers.GetAll(msg.channelID);
              csArray<PublishDestination> destArray;
              for (size_t i = 0; i < subscribers.GetSize(); i++)
              {
                  destArray.Push(PublishDestination(subscribers[i], NULL, 0, 0));
                  Client *target = psserver->GetConnections()->Find(subscribers[i]);
                  if (target && target->IsReady())
                      target->GetActor()->LogChatMessage(client->GetActor()->GetFirstName(), newMsg);
              }

              newMsg.Multicast(destArray, 0, PROX_LIST_ANY_RANGE );
              break;
          }
          case CHAT_PET_ACTION:
          {
              gemNPC *pet = NULL;

              // Check if a specific pet's name was specified, in one of these forms:
              // - /mypet Petname ...
              // - /mypet Petname's ...
              size_t numPets = client->GetNumPets();
              for (size_t i = 0; i < numPets; i++)
              {
                  if ((pet = dynamic_cast <gemNPC*>(client->GetPet(i)))
                      && msg.sText.StartsWith(pet->GetCharacterData()->GetCharName(), true))
                  {
                      size_t n = strlen(pet->GetCharacterData()->GetCharName());
                      if (msg.sText.Length() >= n + 1 && msg.sText.GetAt(n) == ' ')
                      {
                          msg.sText.DeleteAt(0, n);
                          msg.sText.LTrim();
                          break;
                      }
                      else if (msg.sText.Length() >= n + 3 && msg.sText.GetAt(n) == '\''
                               && msg.sText.GetAt(n + 1) == 's' && msg.sText.GetAt(n + 2) == ' ')
                      {
                          msg.sText.DeleteAt(0, n);
                          break;
                      }
                  }
                  else pet = NULL;
              }
              // If no particular pet was specified, assume the default familiar...
              if (!pet)
                  pet = dynamic_cast <gemNPC*>(client->GetFamiliar());

              // Send the message or an appropriate error...
              if (!pet)
                  psserver->SendSystemInfo(me->clientnum, "You have no familiar to command.");
              else
                  SendSay(client->GetClientNum(), pet, msg, pet->GetCharacterData()->GetCharFullName());

              break;
          }
          case CHAT_SAY:
          {
              // Send to all if there's no NPC response or the response is public
              SendSay(client->GetClientNum(), client->GetActor(), msg, client->GetName());
              break;
          }
          case CHAT_NPC:
          {
              // Only the speaker sees his successful chatting with an npc.
              // This helps quests stay secret.
              //psChatMessage newMsg(client->GetClientNum(), client->GetName(), 0,
            //    msg.sText, msg.iChatType, msg.translate);
              //newMsg.SendMessage();
              saveFlood = false;

              gemObject *target = client->GetTargetObject();
              gemNPC *targetnpc = dynamic_cast<gemNPC*>(target);
              NpcResponse *resp = CheckNPCResponse(msg,client,targetnpc);
              if (resp)
              {
                  csTicks delay = resp->ExecuteScript(client->GetActor(), targetnpc);
                  if (delay != (csTicks)-1 && resp->menu )
                      resp->menu->ShowMenu(client, delay, targetnpc);
              }
              break;
          }
          case CHAT_AWAY:
          {
              saveFlood = false; //do not check Away messages for flooding
              msg.iChatType = CHAT_TELL; //do regard it as tell message from now on
              //intentionally no break, so it falls through to CHAT_TELL
          }
          case CHAT_TELL:
          {
              if ( msg.sPerson.Length() == 0 )
              {
                  psserver->SendSystemError(client->GetClientNum(), "You must specify name of player.");
                  break;
              }

              Client *target = FindPlayerClient(msg.sPerson);
              if (target && !target->IsSuperClient())
              {
                  if (!target->IsReady())
                      psserver->SendSystemError(client->GetClientNum(), "%s is not ready yet.", msg.sPerson.GetDataSafe());
                  else
                      SendTell(msg, client->GetName(), client, target);
              }
              else
                  psserver->SendSystemError(client->GetClientNum(), "%s is not found online.", msg.sPerson.GetDataSafe());

              break;
          }
          case CHAT_REPORT:
          {
              // First thing to extract the name of the player to log
              csString targetName;
              int index = (int)msg.sText.FindFirst(' ', 0);
              targetName = (index == -1) ? msg.sText : msg.sText.Slice(0, index);
              targetName = NormalizeCharacterName(targetName);

              if ( targetName.Length() == 0 )
              {
                  psserver->SendSystemError(client->GetClientNum(), "You must specify name of player.");
                  break;
              }

              Client * target = psserver->GetConnections()->Find(targetName);
              if ( !target )
              {
                  psserver->SendSystemError(client->GetClientNum(), "%s is not found online.", targetName.GetData());
                  break;
              }
              if (target->IsSuperClient())
              {
                  psserver->SendSystemError(client->GetClientNum(), "Can't report NPCs.");
                  break;
              }

              // Add an active report to the target.
              if (target->GetActor()->AddChatReport(client->GetActor()))
              {
                  // Add report removal event.
                  psserver->GetEventManager()->Push(new psEndChatLoggingEvent(target->GetClientNum(), 300000));
                  psserver->SendSystemInfo(client->GetClientNum(), "Last 5 minutes of %s's chat were logged. Logging will continue for another 5 minutes.", targetName.GetData());
              }
              else
                  psserver->SendSystemError(client->GetClientNum(), "Could not start logging %s, due to a server error.", targetName.GetData());
              break;
         }
         case CHAT_ADVISOR:
         case CHAT_ADVICE:
             break;

         default:
         {
              Error2("Unknown Chat Type: %d\n",msg.iChatType);
              break;
         }
       }
    }
    else
    {
        //User is muted but tries to chat anyway. Remind the user that he/she/it is muted
        psserver->SendSystemInfo(client->GetClientNum(),"You can't send messages because you are muted.");
    }

    if (saveFlood)
        client->FloodControl(msg.iChatType, msg.sText, msg.sPerson);
}
void CombatManager::AttackSomeone(gemActor *attacker,gemObject *target,Stance stance)
{
    psCharacter *attacker_character = attacker->GetCharacterData();

    //we don't allow an overweight or defeated char to fight
    if (attacker->GetMode() == PSCHARACTER_MODE_DEFEATED || 
        attacker->GetMode() == PSCHARACTER_MODE_OVERWEIGHT)
        return;

    if (attacker->GetMode() == PSCHARACTER_MODE_COMBAT)  // Already fighting
    {
        SetCombat(attacker,stance);  // switch stance from Bloody to Defensive, etc.
        return;
    }
    else
    {
        if (attacker->GetMode() == PSCHARACTER_MODE_SIT) //we are sitting force the char to stand
            attacker->Stand();
        attacker_character->ResetSwings(csGetTicks());
    }

    // Indicator of whether any weapons are available to attack with
    bool startedAttacking=false;
    bool haveWeapon=false;

    // Step through each current slot and queue events for all that can attack
    for (int slot=0; slot<PSCHARACTER_SLOT_BULK1; slot++)
    {
        // See if this slot is able to attack
        if (attacker_character->Inventory().CanItemAttack((INVENTORY_SLOT_NUMBER) slot))
        {
            INVENTORY_SLOT_NUMBER weaponSlot = (INVENTORY_SLOT_NUMBER) slot;
            // Get the data for the "weapon" that is used in this slot
            psItem *weapon=attacker_character->Inventory().GetEffectiveWeaponInSlot(weaponSlot);

            csString response;
            if (weapon!=NULL && weapon->CheckRequirements(attacker_character,response) )
            {
                haveWeapon = true;
                Debug5(LOG_COMBAT,attacker->GetClientID(),"%s tries to attack with %s weapon %s at %.2f range",
                       attacker->GetName(),(weapon->GetIsRangeWeapon()?"range":"melee"),weapon->GetName(),
                       attacker->RangeTo(target,false));
                Debug3(LOG_COMBAT,attacker->GetClientID(),"%s started attacking with %s",attacker->GetName(),
                       weapon->GetName());
                
                // start the ball rolling
                QueueNextEvent(attacker,weaponSlot,target,attacker->GetClientID(),target->GetClientID());  
                
                startedAttacking=true;
            }
            else
            {
                if( weapon  && attacker_character->GetActor())
                {
                    Debug3(LOG_COMBAT,attacker->GetClientID(),"%s tried attacking with %s but can't use it.",
                           attacker->GetName(),weapon->GetName());
#ifdef COMBAT_DEBUG
                    psserver->SendSystemError(attacker_character->GetActor()->GetClientID(), response);
#endif
                } 
            }
        }
    }

    /* Only notify the target if any attacks were able to start.  Otherwise there are
     * no available weapons with which to attack.
     */
    if (haveWeapon)
    {
        if (startedAttacking)
        {
            // The attacker should now enter combat mode
            if (attacker->GetMode() != PSCHARACTER_MODE_COMBAT)
            {
                SetCombat(attacker,stance);
            }
        }
        else
        {
            psserver->SendSystemError(attacker->GetClientID(),"You are too far away to attack!");
            return;
        }
    }
    else
    {
        psserver->SendSystemError(attacker->GetClientID(),"You have no weapons equipped!");
        return;
    }
}