summaryrefslogtreecommitdiffstats
path: root/src/server/ChatRoom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/ChatRoom.cpp')
-rw-r--r--src/server/ChatRoom.cpp360
1 files changed, 360 insertions, 0 deletions
diff --git a/src/server/ChatRoom.cpp b/src/server/ChatRoom.cpp
new file mode 100644
index 0000000..a78670c
--- /dev/null
+++ b/src/server/ChatRoom.cpp
@@ -0,0 +1,360 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ChatRoom.hpp"
+#include "ChatServer.hpp"
+#include "UserInfo.hpp"
+
+#define DB_BUFFER_SIZE 128
+#define USE_IN_ROOM 0
+#define USE_IN_LOBBY 1
+#define USE_ANYWHERE 2
+
+static char **ParseToArg(const char *input, int &arrc);
+static unsigned long hash(const char *str);
+static bool checkForbiddenSymbols(const char *str);
+
+struct cmd_info {
+ int id; // never -1 !!!
+ char name[15];
+ const unsigned long name_hash;
+ int lobby_cmd; // USE_IN_ROOM, USE_IN_LOBBY, USE_ANYWHERE
+ int min_argc;
+ char usage[64];
+};
+
+const int cmd_id_help = 0;
+const int cmd_id_create = 1;
+const int cmd_id_join = 2;
+const int cmd_id_exit = 3;
+const int cmd_id_rooms = 4;
+
+const int cmd_count = 5;
+const struct cmd_info cmd[cmd_count] = {
+ {cmd_id_help, "/help", hash("/help"), USE_ANYWHERE, 0, "Usage: /help"},
+ {cmd_id_create, "/create", hash("/create"), USE_IN_LOBBY, 0, "Usage: /create [pass-key]"},
+ {cmd_id_join, "/join", hash("/join"), USE_IN_LOBBY, 1, "Usage: /join *id* [pass-key]"},
+ {cmd_id_exit, "/exit", hash("/exit"), USE_IN_ROOM, 0, "Usage: /exit"},
+ {cmd_id_rooms, "/rooms", hash("/rooms"), USE_IN_LOBBY, 0, "Usage: /rooms"} // print all public rooms
+
+ // IDEA: /clear - clear screen
+};
+
+ChatRoom::ChatRoom(ChatServer *i_server, int id, char *pass)
+ : the_server(i_server), code(id), first(0)
+{
+ if(pass)
+ strcpy(secret_pass, pass);
+ else secret_pass[0] = 0;
+}
+
+ChatRoom::~ChatRoom()
+{
+ while(first) {
+ item *tmp = first;
+ first = first->next;
+ the_server->CloseConnection(tmp->u);
+ delete tmp;
+ }
+}
+
+void ChatRoom::SendAll(const char *msg, UserInfo *except,
+ const int spec_msg)
+{
+ CONSOLE_LOG("Send message all: %s\n", msg);
+ item *p;
+ for(p = first; p; p = p->next)
+ if(p->u != except)
+ p->u->Send(msg, spec_msg);
+}
+
+void ChatRoom::HandleMessage(UserInfo *u, const char *str)
+{
+ int status = u->GetStatus();
+ if(status != no_wait) {
+ if(status == wait_name) {
+ // handle name, if OK - will send hello msg
+ int len = strlen(str);
+ if(len > max_name_len || len < min_name_len) {
+ u->Send("Incorrect name. Name length from 3 to 18 chars");
+ CloseSession(u);
+ }
+ if(checkForbiddenSymbols(str)) {
+ u->Send("Incorrect name. You use forbidden symbols.");
+ CloseSession(u);
+ }
+
+ //if(userInServer(char *nickname))
+ // проверить если кто-то с данным именем..
+
+ u->SetName(str);
+
+ char *msg = new char[DB_BUFFER_SIZE];
+ sprintf(msg, "SELECT password FROM users WHERE name = '%s' LIMIT 1", str);
+ CONSOLE_LOG("%s\n", msg);
+ AnswerDB *ans = the_server->QuerySelect(msg);
+ if(ans) {
+ DB_ROW *row = ans->GetNextRow();
+
+ char *pass = 0;
+ if(row) {
+ pass = new char[max_player_lenpass];
+ strcpy(pass, (*row)[0]);
+
+ CONSOLE_LOG("account exist! \n");
+ }
+ }
+ else CONSOLE_LOG("account noexist :( \n");
+ delete[] msg;
+
+ u->Send("Welcome to WantChat!");
+ u->Send(" ");
+ u->Send("It is anonymous chat in retro-style 80s.");
+ u->Send("Use our chat-client for more immersed.");
+ u->Send(" ");
+ u->Send("This project is open source :)");
+ u->Send("Github: github.com/Joursoir/want-chat");
+ u->Send(" ");
+ u->Send("To join to room using /join room_id");
+ u->Send("You can find rooms using /rooms");
+ u->Send(" ");
+ u->Send("For more detailed info: /help. Good chatting!");
+ u->Send(" ");
+
+ u->SetStatus(no_wait);
+ }
+
+ return;
+ }
+
+ if(str[0] == '/') { // if user sent a command
+ int argc = 0;
+ char **argv = ParseToArg(str, argc);
+ this->HandleCommand(u, argc, argv);
+
+ for(int i = 0; i < argc; i++)
+ delete[] argv[i];
+ delete[] argv;
+ }
+ else if(code != std_id_lobby) {
+ char *msg = new char[max_msg_len];
+ sprintf(msg, "%s: %s", u->GetName(), str);
+
+ this->SendAll(msg, 0, usual_msg);
+
+ delete[] msg;
+ }
+ else u->Send("In the lobby you can only write commands");
+}
+
+void ChatRoom::HandleCommand(UserInfo *u, int count,
+ char **argvar)
+{
+ unsigned long hash_cmd = -1;
+ hash_cmd = hash(argvar[0]);
+
+ int what_command = -1;
+ for(int i = 0; i < cmd_count; i++) {
+ if(cmd[i].name_hash == hash_cmd) {
+ what_command = i;
+ break;
+ }
+ }
+
+ if(what_command == -1)
+ return u->Send("Unknown command. Use: /help");
+
+ const char onlyroom_msg[] = "You can use this command only in rooms!";
+ const char onlylobby_msg[] = "You can use this command only in lobby!";
+
+ // scope of command:
+ if(cmd[what_command].lobby_cmd == USE_IN_ROOM && code == std_id_lobby)
+ return u->Send(onlyroom_msg);
+ else if(cmd[what_command].lobby_cmd == USE_IN_LOBBY && code != std_id_lobby)
+ return u->Send(onlylobby_msg);
+
+ // right usage:
+ if(cmd[what_command].min_argc > count-1)
+ return u->Send(cmd[what_command].usage);
+
+ switch(cmd[what_command].id) {
+ case cmd_id_help: {
+ u->Send("Help info...");
+ break;
+ }
+ case cmd_id_create: {
+ char *pass = 0;
+ if(count > 1) {
+ if(strlen(argvar[1]) > max_room_lenpass)
+ return u->Send("Maximum length of pass equals 24");
+ pass = argvar[1];
+ }
+ int id = the_server->AddRoom(pass);
+
+ const char fcmsg[] = "You create a room #";
+ const char scmsg[] = " with password: ";
+ char *cmsg = new char[strlen(fcmsg)+3+strlen(scmsg)+max_room_lenpass];
+ if(pass) sprintf(cmsg, "%s%d%s%s", fcmsg, id, scmsg, pass);
+ else sprintf(cmsg, "%s%d", fcmsg, id);
+ u->Send(cmsg);
+ delete[] cmsg;
+
+ the_server->ChangeSessionRoom(this, u, id, pass);
+ break;
+ }
+ case cmd_id_join: {
+ int id = atoi(argvar[1]);
+ char *pass = argvar[2]; // if count == 2, then argvar[2] = 0
+
+ int h_status = the_server->ChangeSessionRoom(this, u, id, pass);
+ if(h_status == enter_noexist)
+ return u->Send("Room with that ID didn't exist");
+ else if(h_status == enter_private)
+ return u->Send("It is private room, join using password");
+ else if(h_status == enter_uncorrect_pass)
+ return u->Send("Oops, this password is not valid");
+
+ u->Send("You has left the room");
+ break;
+ }
+ case cmd_id_exit: {
+ the_server->GotoLobby(this, u);
+ break;
+ }
+ case cmd_id_rooms: {
+ // in development
+ break;
+ }
+ default: break;
+ }
+}
+
+const char *ChatRoom::GetSecretPass()
+{
+ if(secret_pass[0] != 0)
+ return secret_pass;
+ return 0;
+}
+
+void ChatRoom::AddSession(UserInfo *u)
+{
+ item *p = new item;
+ p->next = first;
+ p->u = u;
+ first = p;
+
+ if(code == std_id_lobby)
+ return;
+
+ const char welcome_msg[] = "Welcome to the room #";
+ const char entered_msg[] = " has entered the room";
+
+ const char *name = u->GetName();
+
+ char *wmsg = new char[sizeof(welcome_msg) + 2];
+ sprintf(wmsg, "%s%d", welcome_msg, code);
+ u->Send(wmsg);
+ delete[] wmsg;
+
+ char *emsg = new char[strlen(name) + sizeof(entered_msg)];
+ sprintf(emsg, "%s%s", name, entered_msg);
+ this->SendAll(emsg, u);
+ delete[] emsg;
+
+}
+
+void ChatRoom::RemoveSession(UserInfo *u)
+{
+ if(code != std_id_lobby) {
+ const char left_msg[] = " has left the room";
+ const char *name = u->GetName();
+
+ int len = strlen(name);
+ char *lmsg = new char[len + sizeof(left_msg) + 2];
+ sprintf(lmsg, "%s%s", name, left_msg);
+ this->SendAll(lmsg, u);
+ delete[] lmsg;
+ }
+
+ item **p;
+ for(p = &first; *p; p = &((*p)->next)) {
+ if( ((*p)->u) == u ) {
+ item *tmp = *p;
+ *p = tmp->next;
+ // not delete UserInfo!
+ delete tmp;
+
+ if(code != std_id_lobby && !first)
+ the_server->DeleteRoom(code);
+
+ return;
+ }
+ }
+}
+
+void ChatRoom::CloseSession(UserInfo *u)
+{
+ ChatServer *serv = the_server;
+ this->RemoveSession(u);
+ serv->CloseConnection(u);
+}
+
+//////////////////////////////////////////////////////////////
+
+static char **ParseToArg(const char *input, int &arrc)
+{
+ int max_argv = 5;
+ arrc = 0;
+ char **arr = new char*[max_argv+1];
+
+ int start = 0;
+ for(int i = 0; i < (int) strlen(input)+1; i++) {
+ if(input[i] == ' ' || input[i] == '\0' || input[i] == '\n') { // end
+ if(start == std_id_lobby)
+ continue;
+
+ int size = i - start;
+ arr[arrc] = new char[size+1];
+ memcpy(arr[arrc], input + start, sizeof(char) * size);
+ arr[arrc][size] = '\0';
+
+ start = -1;
+ arrc++;
+ if(arrc == max_argv)
+ break;
+ }
+ else if(start == -1)
+ start = i;
+ }
+
+ arr[arrc] = 0;
+ return arr;
+}
+
+static unsigned long hash(const char *str)
+{
+ unsigned long hash = 5381;
+ char c;
+
+ while( (c = *str++) )
+ hash = ((hash << 5) + hash) + c;
+
+ return hash;
+}
+
+static bool checkForbiddenSymbols(const char *str)
+{
+ char banned_symbols[] = {'!', '@', '#', '\'',
+ '\"', '\\', '/', '^', '&', '*', ';', ','};
+
+ int num = sizeof(banned_symbols)/sizeof(char);
+ for(int i = 0; i < (int)strlen(str); i++) {
+ for(int j = 0; j < num; j++) {
+ if(str[i] == banned_symbols[j])
+ return 1;
+ }
+ }
+
+ return 0;
+} \ No newline at end of file