diff --git a/src/client.h b/src/client.h index 8182326..6cb0c01 100644 --- a/src/client.h +++ b/src/client.h @@ -1,29 +1,39 @@ #ifndef H_CLIENT #define H_CLIENT -#include +#include +#include #include "drone.h" -#define SERVERADDR "209.240.84.122" -#define AUTOSERVER 6650 -#define ROOMSERVER 5672 -// This should be your MTU, but I don't have a method for auto-detecting that. -#define BUFFERSIZE 1440 +#define BUFFERSIZE 65535 +bool netstatus = false; + WINDOW* wlog; WINDOW* wform; FORM *form; FIELD *entries[1]; -char* protocol = "24"; +int autosock; +int roomsock; + +std::thread aRecv_t; +std::thread rRecv_t; +std::thread rKA_t; + +char* worldsserver = "209.240.84.122"; +uint16_t autoport = 6650; +uint16_t roomport = 5672; + +int protocol = 24; char* version = "0000000000"; -char* default_avatar = "avatar:pengo.mov"; -char* avatars = "1024"; +char* avatar = "avatar:pengo.mov"; +int avatars = 253; char* room = "GroundZero#Reception"; char* dimension = "dimension-1"; uint16_t roomID = 1; -char login_username[128]; -char login_password[128]; +char login_username[16]; +char login_password[16]; uint16_t xPos = 0; uint16_t yPos = 0; @@ -40,12 +50,14 @@ std::vector mutes; static char* trim(char *str); char* zero(int size); unsigned char* uzero(int size); -void autoInit(int sock_fd); -void roomInit(int sock_fd); -void reciever(int sock_fd); +void autoInit(); +void roomInit(); +void roomKeepAlive(); +void reciever(int sock_fd, bool autoserver); void sessInit(int sock_fd, char* username, char* password); void sessExit(int sock_fd); void readPropertyList(unsigned char* in); +std::map readOldPropertyList(unsigned char* in); void setAvatar(int sock_fd, char* avatar); void roomIDReq(int sock_fd, char* room); void teleport(int sock_fd, int x, int y, int z, int rot); diff --git a/src/main.cpp b/src/main.cpp index 7c82caf..8ec33de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include #include +#include #include #include #include @@ -16,6 +16,7 @@ #include "client.h" #include "var_error.h" #include "cmds.h" +#include "props.h" static char* trim(char *str) { char *end; @@ -29,29 +30,27 @@ static char* trim(char *str) { *(end+1) = '\0'; return str; } - +struct sockaddr_in auto_addr; +struct sockaddr_in room_addr; int main(int argc, char const* argv[]) { unsigned char bufout[BUFFERSIZE] = {0}; - int status, valread, autosock, roomsock; - struct sockaddr_in serv_addr; - std::cout << "Username: "; std::cin >> login_username; + auto_addr.sin_family = AF_INET; + inet_pton(AF_INET, worldsserver, &auto_addr.sin_addr); + auto_addr.sin_port = htons(autoport); + + room_addr.sin_family = AF_INET; + inet_pton(AF_INET, worldsserver, &room_addr.sin_addr); + room_addr.sin_port = htons(roomport); initscr(); cbreak(); noecho(); - refresh(); - - printf("*Password: "); - std::cin >> login_password; wlog = newwin(LINES-1, COLS, 0, 0); - wmove(wlog, LINES-2, 0); scrollok(wlog, true); - wprintw(wlog, "\n*Connecting to Worlds.com. Enter '.help' for a list of commands."); wform = newwin(1, COLS, LINES-1, 0); - wmove(wform, 0, 0); scrollok(wform, true); keypad(wform, TRUE); @@ -63,33 +62,17 @@ int main(int argc, char const* argv[]) { form = new_form(entries); set_form_win(form, wform); post_form(form); - set_current_field(form, entries[0]); - if ((autosock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - perror("Socket creation error."); - - serv_addr.sin_family = AF_INET; - inet_pton(AF_INET, SERVERADDR, &serv_addr.sin_addr); - serv_addr.sin_port = htons(AUTOSERVER); - - if ((status = connect(autosock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) < 0) - perror("AutoServ connection failed."); - - // Initialize connection. - std::thread aRecv_t(reciever, autosock); - autoInit(autosock); - - serv_addr.sin_port = htons(ROOMSERVER); - close(autosock); - if ((roomsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - perror("Socket creation error."); - - if ((status = connect(roomsock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))) < 0) - perror("RoomServ connection failed"); - - std::thread rRecv_t(reciever, roomsock); - std::thread rInit_t(roomInit, roomsock); + pos_form_cursor(form); + wmove(wform, 0, 0); + wrefresh(wform); + wmove(wlog, LINES-2, 0); + wrefresh(wlog); + refresh(); + wprintw(wlog, "\n*Welcome to WorldsTerm. Enter '.help' for a list of commands."); + wprintw(wlog, "\n*To get started, '.connect' to the server and '.login'."); + wrefresh(wlog); int key = 0; while ((key = wgetch(wform))) { @@ -97,6 +80,7 @@ int main(int argc, char const* argv[]) { if (key == 10) { form_driver(form, REQ_VALIDATION); char* inmsg = trim(field_buffer(entries[0], 0)); + set_field_buffer(entries[0], 0, ""); int msglen = 0; if ((msglen = strlen(inmsg)) > 0) { if (inmsg[0] == '.' && msglen > 1) { // Starting a command. @@ -139,6 +123,34 @@ int main(int argc, char const* argv[]) { inmsg = new char[256]; srcLine = 0; } + } else if (strcmp(cmd, "connect") == 0) { + autoInit(); + } else if (strcmp(cmd, "disconnect") == 0) { + if (aRecv_t.joinable()) aRecv_t.detach(); + wsend(autosock, new unsigned char[] {0x03, 0x01, CMD_SESSEXIT}, 0); + } else if (strcmp(cmd, "login") == 0) { + char username[16] = {0}; j = 0; + while (msgoff < msglen && (s = inmsg[msgoff++]) != 0x20) { + username[j++] = s; + } + username[j++] = 0; + char password[16] = {0}; j = 0; + while (msgoff < msglen && (s = inmsg[msgoff++]) != 0x00) { + password[j++] = s; + } + password[j++] = 0; + + if (strlen(username) == 0 || strlen(password) == 0) { wprintw(wlog, "\n*.login "); continue; } + int u = 0; + for(u; u < strlen(username); u++) + login_username[u] = username[u]; + login_username[u]; + int p = 0; + for(p; p < strlen(password); p++) + login_password[p] = password[p]; + login_password[p]; + wprintw(wlog, "\n*Logging in as %s.", username); + sessInit(autosock, username, password); } else if ((strcmp(cmd, "w") == 0 || strcmp(cmd, "whisper") == 0) && srcLine < 0) { int k = 1; bufout[k++] = 0; @@ -368,6 +380,9 @@ int main(int argc, char const* argv[]) { wprintw(wlog, "%s %s", _f?",":"", value.name); _f=true; } + } else if (strcmp(cmd, "logout") == 0) { + wsend(autosock, new unsigned char[] {0x03, 0x01, CMD_SESSEXIT}, 0); + wsend(roomsock, new unsigned char[] {0x03, 0x01, CMD_SESSEXIT}, 0); } else if (strcmp(cmd, "q") == 0) { goto quit; } else { @@ -396,7 +411,6 @@ int main(int argc, char const* argv[]) { wsend(roomsock, bufout, 0); } bufout[0] = 0; - set_field_buffer(entries[0], 0, ""); } } else if (key == KEY_LEFT) { form_driver(form, REQ_PREV_CHAR); @@ -427,32 +441,44 @@ int main(int argc, char const* argv[]) { return 0; } -void autoInit(int sock_fd) { - wsend(sock_fd, new unsigned char[] {0x03, 0xff, CMD_PROPREQ}, 0); - sleep(1); - sessInit(sock_fd, login_username, login_password); - sleep(1); - setAvatar(sock_fd, default_avatar); - roomIDReq(sock_fd, room); +void autoInit() { + if ((autosock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + perror("AutoSock creation error"); - pos_form_cursor(form); - wrefresh(wform); wrefresh(wlog); - refresh(); + if (connect(autosock, (struct sockaddr*)&auto_addr, sizeof(auto_addr)) < 0) + perror("AutoServ connection failed"); + + wprintw(wlog, "\n*Connected to AutoServer %s:%i", worldsserver, autoport); + // Initialize connection. + aRecv_t = std::thread(reciever, autosock, true); + wsend(autosock, new unsigned char[] {0x03, 0xff, CMD_PROPREQ}, 0); + wrefresh(wlog); + netstatus = true; } -void roomInit(int sock_fd) { - wsend(sock_fd, new unsigned char[] {0x03, 0xff, CMD_PROPREQ}, 0); - sleep(1); - sessInit(sock_fd, login_username, login_password); - setAvatar(sock_fd, default_avatar); - while (true) { - teleport(sock_fd, xPos, yPos, zPos, rot); - sleep(15); +void roomInit() { + if ((roomsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + perror("AutoSock creation error"); + + if ((connect(roomsock, (struct sockaddr*)&room_addr, sizeof(room_addr))) < 0) + perror("RoomServ connection failed"); + wprintw(wlog, "\n*Connected to RoomServer %s:%i", worldsserver, roomport); + rRecv_t = std::thread(reciever, roomsock, false); + rKA_t = std::thread(roomKeepAlive); + sessInit(roomsock, login_username, login_password); + login_password[0] = 0; + wrefresh(wlog); +} + +void roomKeepAlive() { + while (netstatus) { + teleport(roomsock, xPos, yPos, zPos, rot); + sleep(5); } } -void reciever(int sock_fd) { +void reciever(int sock_fd, bool autoserver = false) { unsigned char bufin[BUFFERSIZE] = {}; unsigned char bufout[BUFFERSIZE] = {}; while (read(sock_fd, bufin, sizeof(bufin)) > 0) { @@ -524,7 +550,73 @@ void reciever(int sock_fd) { objects[shortID] = newDrone; } } else if (bufin[p+2] == CMD_SESSEXIT && bufin[p+1] == 0x01) { - break; + close(sock_fd); + if (autoserver) { + wprintw(wlog, "\n*Logged out of %s.", login_username); + login_username[0] = 0; + + // Clear + properties.erase(properties.begin(), properties.end()); + objects.erase(objects.begin(), objects.end()); + rooms.erase(rooms.begin(), rooms.end()); + friends.clear(); + mutes.clear(); + + aRecv_t.detach(); + netstatus = false; + wprintw(wlog, "\n*Disconnected!", sock_fd); + } else { + wprintw(wlog, "\n*Leaving room %s<%s>", room, dimension); + roomID = 1; + room = "GroundZero#Reception"; + dimension = "dimension-1"; + xPos = 0; + yPos = 0; + zPos = 0; + rot = 0; + + rRecv_t.detach(); + rKA_t.detach(); + } + } else if (bufin[p+2] == CMD_SESSINIT && bufin[p+1] == 0x01) { + std::map props = readOldPropertyList(&bufin[p]); + int err = VAR_FATAL; + for (const auto& [key, value] : props) { + switch (key) { + case PROP_ERROR: + err = atoi(value); + break; + } + } + if (err != VAR_OK) { + char* errMsg = "UNKNOWN"; + switch(err) { + case VAR_BAD_PASSWORD: + errMsg = "Invalid Password."; break; + case VAR_BAD_ACCOUNT: + errMsg = "Account is no longer valid."; break; + case VAR_BAD_IPADDRESS: + errMsg = "Invalid client IP address!"; break; + case VAR_NO_SUCH_USER: + errMsg = "User does not exist."; break; + } + wprintw(wlog, "\n*Error %i: %s", err, errMsg); + + if (autoserver) { + aRecv_t.detach(); + netstatus = false; + } else { + rRecv_t.detach(); + rKA_t.detach(); + } + } else { + if (!autoserver) { + memset(&(login_password[0]), 0, sizeof(login_password)); + setAvatar(sock_fd, avatar); + } else { + roomIDReq(sock_fd, room); + } + } } else if ((bufin[p+2] == CMD_ROOMID || bufin[p+2] == 0x1A) && bufin[p+1] == 0x01) { char *longID = new char[255]; int shortID; @@ -536,6 +628,7 @@ void reciever(int sock_fd) { shortID = ((uint16_t)bufin[offs++] << 8) | bufin[offs++]; rooms[longID] = shortID; roomID = shortID; + if (autoserver) roomInit(); wprintw(wlog, "\n*Joining room %s", longID); for (const auto& [key, value] : objects) { objects.erase((char)key); @@ -579,6 +672,7 @@ void reciever(int sock_fd) { } memset(&(bufin[0]), 0, sizeof(bufin)); } + wrefresh(wlog); } void sessInit(int sock_fd, char* name, char* pass) { @@ -600,16 +694,20 @@ void sessInit(int sock_fd, char* name, char* pass) { bufout[l++] = pass[c]; // Protocol + char* pstr = new char[4]; + sprintf(pstr, "%d", protocol); bufout[l++] = 3; - bufout[l++] = strlen(protocol); - for (int c = 0; c < strlen(protocol); c++) - bufout[l++] = protocol[c]; + bufout[l++] = strlen(pstr); + for (int c = 0; c < strlen(pstr); c++) + bufout[l++] = pstr[c]; // Avatars + char* avstr = new char[4]; + sprintf(avstr, "%d", avatars); bufout[l++] = 7; - bufout[l++] = strlen(avatars); - for (int c = 0; c < strlen(avatars); c++) - bufout[l++] = avatars[c]; + bufout[l++] = strlen(avstr); + for (int c = 0; c < strlen(avstr); c++) + bufout[l++] = avstr[c]; // Version bufout[l++] = 9; @@ -663,6 +761,21 @@ void readPropertyList(unsigned char* in) { } } +std::map readOldPropertyList(unsigned char* in) { + std::map oldprops = {}; + int l {3}; + while (l < in[0]) { + char* value = new char[255]; + char type = in[l++]; + int len = in[l++]; + memcpy(value, &in[l], len); + l+=len; + value[len]=0; + oldprops[type] = value; + } + return oldprops; +} + /* void readPropertyList(unsigned char* in) { int l {3}; @@ -772,4 +885,4 @@ void userExit(char id) { int wsend(int sock_fd, unsigned char str[], int flags) { return send(sock_fd, str, str[0], flags); -} +} \ No newline at end of file diff --git a/src/props.h b/src/props.h new file mode 100644 index 0000000..d835976 --- /dev/null +++ b/src/props.h @@ -0,0 +1,32 @@ +#ifndef PROPS_H +#define PROPS_H + +#define PROP_APPNAME 1 +#define PROP_USERNAME 2 +#define PROP_PROTOCOL 3 +#define PROP_ERROR 4 +#define PROP_CHANNEL 5 +#define PROP_PASSWORD 6 +#define PROP_AVATARS 7 +#define PROP_UPDATETIME 8 +#define PROP_CLIENT 9 +#define PROP_SERIAL 10 +#define PROP_EMAIL 11 +#define PROP_LOGONOFF 12 +#define PROP_DURATION 13 +#define PROP_GUEST 14 +#define PROP_SERVERTYPE 15 +#define PROP_BIZCARD 16 +#define PROP_NEW_PASSWORD 20 +#define PROP_PRIV 22 +#define PROP_ASLEEP 23 +#define PROP_EX_HTTP_SERVER 24 +#define PROP_SCRIPT_SERVER 25 +#define PROP_SMTP_SERVER 26 +#define PROP_MAIL_DOMAIN 27 +#define PROP_NEW_USERNAME 28 +#define PROP_IN_HTTP_SERVER 29 +#define PROP_INVENTORY 30 + +#endif + diff --git a/src/var_error.h b/src/var_error.h index 0a38a2f..b05144b 100644 --- a/src/var_error.h +++ b/src/var_error.h @@ -1,7 +1,7 @@ #ifndef H_VAR_ERROR #define H_VAR_ERROR -#define VAR_OK 0 | 200 +#define VAR_OK 0 #define VAR_BAD_USER 1 #define VAR_MAX_ORDINARY 2 #define VAR_MAX_PRIORITY 3