/* * Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef WIN32 #include "windows.h" #endif #include #include #if defined(POSIX) #include #include #endif #include "chat_api.h" #include "grdefs.h" #include "mtstrings.h" #include "networking.h" extern const char *GetString(int d); typedef void *(*mem_malloc_fp)(int size); extern mem_malloc_fp DLLmem_malloc; typedef void (*mem_free_fp)(void *memblock); extern mem_free_fp DLLmem_free; typedef int (*nw_Asyncgethostbyname_fp)(uint32_t *ip, int command, const char *hostname); extern nw_Asyncgethostbyname_fp DLLnw_Asyncgethostbyname; typedef int (*PollUI_fp)(); extern PollUI_fp DLLPollUI; #ifndef RELEASE #define DLLmprintf(...) DLLDebug_ConsolePrintf(__VA_ARGS__) #else #define DLLmprintf(...) #endif typedef void (*Debug_ConsolePrintf_fp)(int n, const char *format, ...); extern Debug_ConsolePrintf_fp DLLDebug_ConsolePrintf; #define MAXCHATBUFFER 500 SOCKET Chatsock; SOCKADDR_IN Chataddr; int Socket_connecting = 0; char Nick_name[33]; char Orignial_nick_name[33]; int Nick_variety = 0; char szChat_channel[33] = ""; char Input_chat_buffer[MAXCHATBUFFER] = ""; char Chat_tracker_id[33]; char Getting_user_channel_info_for[33] = ""; char Getting_user_tracker_info_for[33] = ""; int Getting_user_channel_error = 0; int Getting_user_tracker_error = 0; char User_req_tracker_id[100] = ""; // These are oversized for saftey char User_req_channel[100] = ""; char *User_list = nullptr; char *Chan_list = nullptr; int Socket_connected = 0; int Chat_server_connected = 0; int Joining_channel = 0; int Joined_channel = 0; int GettingChannelList = 0; int GettingUserTID = 0; int GettingUserChannel = 0; Chat_user *Firstuser, *Curruser; Chat_command *Firstcommand, *Currcommand; Chat_channel *Firstchannel, *Currchannel; void ChatInit() { Socket_connecting = 0; Nick_name[0] = 0; Orignial_nick_name[0] = 0; Nick_variety = 0; szChat_channel[0] = '\0'; Input_chat_buffer[0] = '\0'; Chat_tracker_id[0] = 0; Getting_user_channel_info_for[0] = '\0'; Getting_user_tracker_info_for[0] = '\0'; Getting_user_channel_error = 0; Getting_user_tracker_error = 0; User_req_tracker_id[0] = '\0'; User_req_channel[0] = '\0'; User_list = nullptr; Chan_list = nullptr; Socket_connected = 0; Chat_server_connected = 0; Joining_channel = 0; Joined_channel = 0; GettingChannelList = 0; GettingUserTID = 0; GettingUserChannel = 0; } // Return codes: //-2 Already connected //-1 Failed to connect // 0 Connecting // 1 Connected // Call it once with the server IP address, and it will return immediately // with 0. Keep calling it until it returns something other than 0 // note: the nickname may be changed if someone with that name already // exists (Scourge1 for instance) int ConnectToChatServer(const char *serveraddr, int16_t chat_port, char *nickname, char *trackerid) { char signon_str[100]; // if(Socket_connected && ) return -2; if (!Socket_connecting) { strcpy(Nick_name, nickname); for (uint32_t l = 0; l < strlen(Nick_name); l++) if (Nick_name[l] == ' ') Nick_name[l] = '_'; strcpy(Orignial_nick_name, nickname); strcpy(Chat_tracker_id, trackerid); Firstuser = nullptr; Firstcommand = nullptr; Chat_server_connected = 0; FlushChatCommandQueue(); if (chat_port == 0) { // AfxMessageBox("Invalid chat port, must be host.com:port (ie. irc.dal.net:6667)"); return -1; } Chatsock = socket(AF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == Chatsock) { // AfxMessageBox("Unable to open socket!"); return -1; } memset(&Chataddr, 0, sizeof(SOCKADDR_IN)); Chataddr.sin_family = AF_INET; Chataddr.sin_addr.s_addr = INADDR_ANY; Chataddr.sin_port = 0; if (SOCKET_ERROR == bind(Chatsock, (SOCKADDR *)&Chataddr, sizeof(sockaddr))) { // AfxMessageBox("Unable to bind socket!"); return -1; } #ifdef WIN32 unsigned long arg = 1; ioctlsocket(Chatsock, FIONBIO, &arg); #else // WIN32 fcntl(Chatsock, F_SETFL, fcntl(Chatsock, F_GETFL, 0) | O_NONBLOCK); #endif /* HOSTENT *he; he = gethostbyname(chat_server); if(!he) { //AfxMessageBox("Unable to gethostbyname.\n"); return -1; } memcpy(&Chataddr.sin_addr.s_addr, he->h_addr_list[0],4);//&iaddr, 4); */ int rcode; uint32_t ip; DLLnw_Asyncgethostbyname(&ip, NW_AGHBN_LOOKUP, serveraddr); do { rcode = DLLnw_Asyncgethostbyname(&ip, NW_AGHBN_READ, serveraddr); if (99 == DLLPollUI()) { return 0; } } while (rcode == 0); if (rcode != 1) { DLLmprintf(0, "Unable to gethostbyname(\"%s\").\n", serveraddr); DLLmprintf(0, "WSAGetLastError() returned %d.\n", WSAGetLastError()); DLLnw_Asyncgethostbyname(nullptr, NW_AGHBN_CANCEL, nullptr); return 0; } memcpy(&Chataddr.sin_addr.s_addr, &ip, 4); Chataddr.sin_port = htons(chat_port); if (SOCKET_ERROR == connect(Chatsock, (SOCKADDR *)&Chataddr, sizeof(SOCKADDR_IN))) { int ret = WSAGetLastError(); #if !defined(POSIX) if (WSAEWOULDBLOCK == WSAGetLastError()) #else if (EINPROGRESS == ret || 0 == ret) #endif { DLLmprintf(0, "Beginning socket connect\n"); Socket_connecting = 1; return 0; } } else { // This should never happen, connect should always return WSAEWOULDBLOCK DLLmprintf(0, "connect returned too soon!\n"); Socket_connecting = 1; Socket_connected = 1; DLLmprintf(0, "Socket connected, sending user and nickname request\n"); snprintf(signon_str, sizeof(signon_str), "/USER %s %s %s :%s", "user", "user", "user", Chat_tracker_id); SendChatString(signon_str, 1); snprintf(signon_str, sizeof(signon_str), "/NICK %s", Nick_name); SendChatString(signon_str, 1); return 0; } } else { if (Chat_server_connected) { return 1; } if (!Socket_connected) { // Do a few select to check for an error, or to see if we are writeable (connected) fd_set write_fds, error_fds; #ifdef WIN32 TIMEVAL timeout; #else struct timeval timeout; #endif timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO(&write_fds); FD_SET(Chatsock, &write_fds); // Writable -- that means it's connected if (select(Chatsock + 1, nullptr, &write_fds, nullptr, &timeout)) { Socket_connected = 1; DLLmprintf(0, "Socket connected, sending user and nickname request\n"); snprintf(signon_str, sizeof(signon_str), "/USER %s %s %s :%s", "user", "user", "user", Chat_tracker_id); SendChatString(signon_str, 1); snprintf(signon_str, sizeof(signon_str), "/NICK %s", Nick_name); SendChatString(signon_str, 1); return 0; // Now we are waiting for Chat_server_connected } FD_ZERO(&error_fds); FD_SET(Chatsock, &error_fds); // error -- that means it's not going to connect if (select(Chatsock + 1, nullptr, nullptr, &error_fds, &timeout)) { DLLmprintf(0, "Select returned an error!\n"); return -1; } return 0; } } return 0; } // Call it to close the connection. It returns immediately void DisconnectFromChatServer() { if (!Socket_connected) return; SendChatString("/QUIT", 1); shutdown(Chatsock, 2); #ifdef WIN32 closesocket(Chatsock); #else close(Chatsock); #endif Socket_connecting = 0; Socket_connected = 0; Input_chat_buffer[0] = '\0'; if (User_list) { DLLmem_free(User_list); User_list = nullptr; } if (Chan_list) { DLLmem_free(Chan_list); Chan_list = nullptr; } Chat_server_connected = 0; Joining_channel = 0; Joined_channel = 0; RemoveAllChatUsers(); FlushChatCommandQueue(); FlushChannelList(); } // returns NULL if no line is there to print, otherwise returns a string to // print (all preformatted of course) const char *GetChatText() { if (!Socket_connected) return nullptr; // ChatGetString will do the formatting return ChatGetString(); } // Send a string to be sent as chat, or scanned for messages (/msg // string) const char *SendChatString(const char *line, int raw) { char szCmd[200]; char szTarget[50]; if (!Socket_connected) return nullptr; if (line[0] == '/') { // Start off by getting the command strcpy(szCmd, GetWordNum(0, line + 1)); if (stricmp(szCmd, "msg") == 0) { strcpy(szTarget, GetWordNum(1, line + 1)); snprintf(szCmd, sizeof(szCmd), "PRIVMSG %s :%s\n\r", szTarget, line + strlen("/msg ") + strlen(szTarget) + 1); send(Chatsock, szCmd, strlen(szCmd), 0); szCmd[strlen(szCmd) - 2] = '\0'; return ParseIRCMessage(szCmd, MSG_LOCAL); } if (stricmp(szCmd, "me") == 0) { snprintf(szCmd, sizeof(szCmd), "PRIVMSG %s :\001ACTION %s\001\n\r", szChat_channel, line + strlen("/me ")); send(Chatsock, szCmd, strlen(szCmd), 0); szCmd[strlen(szCmd) - 2] = '\0'; return ParseIRCMessage(szCmd, MSG_LOCAL); } if (stricmp(szCmd, "xyz") == 0) { // Special command to send raw irc commands snprintf(szCmd, sizeof(szCmd), "%s\n\r", line + strlen("/xyz ")); send(Chatsock, szCmd, strlen(szCmd), 0); return nullptr; } if (stricmp(szCmd, "list") == 0) { snprintf(szCmd, sizeof(szCmd), "%s\n\r", line + 1); send(Chatsock, szCmd, strlen(szCmd), 0); return nullptr; } if (raw) { snprintf(szCmd, sizeof(szCmd), "%s\n\r", line + 1); send(Chatsock, szCmd, strlen(szCmd), 0); return nullptr; } return "Unrecognized command"; } else { if (szChat_channel[0]) { snprintf(szCmd, sizeof(szCmd), "PRIVMSG %s :%s\n\r", szChat_channel, line); send(Chatsock, szCmd, strlen(szCmd), 0); szCmd[strlen(szCmd) - 2] = '\0'; return ParseIRCMessage(szCmd, MSG_LOCAL); } } return nullptr; } // Returns a structure which contains a command and possible some data (like // a user joining or leaving) if one is waiting // This tells you if you need to add a user from the userlist, remove a user, // etc. Also for status messages, like if you get knocked // off the server for some reason. Chat_command *GetChatCommand() { if (!Socket_connected) return nullptr; return GetChatCommandFromQueue(); } // This function returns a list of users in the current channel, in one // string, separated by spaces, terminated by a null // (Spaces aren't allowed as part of a nickname) char *GetChatUserList() { int iuser_list_length = 0; ; if (User_list) { DLLmem_free(User_list); User_list = nullptr; } if (!Socket_connected) return nullptr; Curruser = Firstuser; while (Curruser) { iuser_list_length += strlen(Curruser->nick_name) + 1; Curruser = Curruser->next; } Curruser = Firstuser; User_list = (char *)DLLmem_malloc(iuser_list_length + 1); User_list[0] = '\0'; while (Curruser) { strcat(User_list, Curruser->nick_name); strcat(User_list, " "); Curruser = Curruser->next; } return User_list; } // Call this to set/join a channel. Since we can't be sure that we will be // able to join that channel, check it for completion // You can't be in more than one channel at a time with this API, so you // leave the current channel before trying to join // a new one. Because of this if the join fails, make sure you try to join // another channel, or the user wont be able to chat //-1 Failed to join // 0 joining // 1 successfully joined int SetNewChatChannel(const char *channel) { char partstr[100]; if (!Socket_connected) return -1; if (Joining_channel == 1) { if (Joined_channel == 1) { // We made it in! Joining_channel = 0; return 1; } else if (Joined_channel == -1) { // Error -- we got a message that the channel was invite only, or we were banned or something Joining_channel = 0; strcpy(szChat_channel, ""); return -1; } } else { if (szChat_channel[0]) { snprintf(partstr, sizeof(partstr), "/PART %s", szChat_channel); SendChatString(partstr, 1); } strcpy(szChat_channel, channel); snprintf(partstr, sizeof(partstr), "/JOIN %s", szChat_channel); SendChatString(partstr, 1); Joining_channel = 1; Joined_channel = 0; } return 0; } const char *ChatGetString() { char ch[2]; char *p; int bytesread = 1; static char return_string[MAXCHATBUFFER]; while ((bytesread != 0) && (bytesread != SOCKET_ERROR)) { bytesread = recv(Chatsock, ch, 1, 0); if (bytesread == SOCKET_ERROR) { uint32_t lerror = WSAGetLastError(); #if !defined(POSIX) if (WSAEWOULDBLOCK != lerror) #else if (WSAEWOULDBLOCK != lerror && 0 != lerror) #endif { DLLmprintf(0, "recv caused an error: %d\n", lerror); } return nullptr; } if (bytesread) { ch[1] = '\0'; // DLLmprintf(0,ch); if ((ch[0] == 0x0a) || (ch[0] == 0x0d)) { if (Input_chat_buffer[0] == '\0') { // Blank line, ignore it return nullptr; } strcpy(return_string, Input_chat_buffer); Input_chat_buffer[0] = '\0'; // DLLmprintf(0,"->|%s\n",return_string); p = ParseIRCMessage(return_string, MSG_REMOTE); return p; } strcat(Input_chat_buffer, ch); } else { // Select said we had read data, but 0 bytes read means disconnected DLLmprintf(0, "Disconnected! Doh!"); AddChatCommandToQueue(CC_DISCONNECTED, nullptr, 0); return nullptr; } } return nullptr; } const char *GetWordNum(int num, const char *l_String) { static char strreturn[600]; static char ptokstr[600]; char seps[10] = " \n\r\t"; char *token, *strstart; strstart = ptokstr; strcpy(ptokstr, l_String); token = strtok(ptokstr, seps); for (int i = 0; i != num; i++) { token = strtok(nullptr, seps); } if (token) { strcpy(strreturn, token); } else { return ""; } // check for the ':' char.... if (token[0] == ':') { // Its not pretty, but it works, return the rest of the string strcpy(strreturn, l_String + ((token - strstart) + 1)); } // return the appropriate response. return strreturn; } int AddChatUser(const char *nickname) { Curruser = Firstuser; while (Curruser) { if (stricmp(nickname, Curruser->nick_name) == 0) return 0; Curruser = Curruser->next; } Curruser = Firstuser; if (Firstuser == nullptr) { Firstuser = (Chat_user *)DLLmem_malloc(sizeof(Chat_user)); // ASSERT(Firstuser); strcpy(Firstuser->nick_name, nickname); Firstuser->next = nullptr; AddChatCommandToQueue(CC_USER_JOINING, nickname, strlen(nickname) + 1); return 1; } else { while (Curruser->next) { Curruser = Curruser->next; } Curruser->next = (Chat_user *)DLLmem_malloc(sizeof(Chat_user)); Curruser = Curruser->next; // ASSERT(Curruser); strcpy(Curruser->nick_name, nickname); Curruser->next = nullptr; AddChatCommandToQueue(CC_USER_JOINING, nickname, strlen(nickname) + 1); return 1; } } int RemoveChatUser(char *nickname) { Chat_user *prv_user = nullptr; Curruser = Firstuser; while (Curruser) { if (stricmp(nickname, Curruser->nick_name) == 0) { if (prv_user) { prv_user->next = Curruser->next; } else { Firstuser = Curruser->next; } AddChatCommandToQueue(CC_USER_LEAVING, Curruser->nick_name, strlen(Curruser->nick_name) + 1); DLLmem_free(Curruser); return 1; } prv_user = Curruser; Curruser = Curruser->next; } return 0; } void RemoveAllChatUsers() { Chat_user *tmp_user = nullptr; Curruser = Firstuser; while (Curruser) { tmp_user = Curruser->next; AddChatCommandToQueue(CC_USER_LEAVING, Curruser->nick_name, strlen(Curruser->nick_name) + 1); DLLmem_free(Curruser); Curruser = tmp_user; } Firstuser = nullptr; } char *ParseIRCMessage(char *Line, int iMode) { char szRemLine[MAXLOCALSTRING]; const char *pszTempStr; char szPrefix[MAXLOCALSTRING]; char szHackPrefix[MAXLOCALSTRING]; char szTarget[MAXLOCALSTRING]; char szNick[MAXLOCALSTRING]; char szCmd[MAXLOCALSTRING]; char szCTCPCmd[MAXLOCALSTRING]; static char szResponse[MAXLOCALSTRING]; int iNickLen; int iPrefixLen = 0; szPrefix[0] = '\0'; szNick[0] = '\0'; if (strlen(Line) >= MAXLOCALSTRING) { return nullptr; } // Nick included.... if (iMode == MSG_REMOTE) { strcpy(szRemLine, Line); // Start by getting the prefix szHackPrefix[0] = '\0'; if (Line[0] == ':') { // pszTempStr = GetWordNum(0, Line + 1); strcpy(szPrefix, pszTempStr); strcpy(szHackPrefix, pszTempStr); strcpy(szRemLine, Line + 1 + strlen(szPrefix)); } // Next, get the Nick pszTempStr = strtok(szHackPrefix, "!"); if (pszTempStr) { strcpy(szNick, pszTempStr); } else { strncpy(szNick, szPrefix, 31); szNick[31] = 0; } // strcpy(NewMsg.Nickname,szNick); iNickLen = strlen(szNick); iPrefixLen = strlen(szPrefix); } else if (iMode == MSG_LOCAL) { strcpy(szRemLine, Line); strcpy(szNick, Nick_name); strcpy(szPrefix, Nick_name); // strcpy(NewMsg.Nickname,szNick); iNickLen = -2; iPrefixLen = -2; } // Next is the command pszTempStr = GetWordNum(0, szRemLine); if (pszTempStr[0]) { strcpy(szCmd, pszTempStr); } else { // Shouldn't ever happen, but we can't be sure of what the host will send us. return nullptr; } // Move the szRemLine string up strcpy(szRemLine, Line + iPrefixLen + strlen(szCmd) + 2); // Now parse the commands! // printf("%s",szCmd); if (stricmp(szCmd, "PRIVMSG") == 0) { pszTempStr = GetWordNum(0, szRemLine); strcpy(szTarget, pszTempStr); strcpy(szRemLine, Line + iPrefixLen + strlen(szCmd) + strlen(szTarget) + 4); if (szRemLine[0] == ':') { strcpy(szCTCPCmd, GetWordNum(0, szRemLine + 1)); if (szCTCPCmd[strlen(szCTCPCmd) - 1] == 0x01) szCTCPCmd[strlen(szCTCPCmd) - 1] = 0x00; } else { strcpy(szCTCPCmd, GetWordNum(0, szRemLine)); if (szCTCPCmd[strlen(szCTCPCmd) - 1] == 0x01) szCTCPCmd[strlen(szCTCPCmd) - 1] = 0x00; } if (szCTCPCmd[0] == 0x01) { // Handle ctcp message strcpy(szRemLine, Line + iPrefixLen + strlen(szCmd) + strlen(szTarget) + strlen(szCTCPCmd) + 6); szRemLine[strlen(szRemLine) - 1] = '\0'; // null out the ending 0x01 if (stricmp(szCTCPCmd + 1, "ACTION") == 0) { // Posture snprintf(szResponse, sizeof(szResponse), "\1\xff\x28\x28* %s %s", szNick, szRemLine); return szResponse; } if (iMode == MSG_LOCAL) { strcpy(szHackPrefix, Line + iPrefixLen + strlen(szCmd) + strlen(szTarget) + 4); szRemLine[strlen(szRemLine) - 1] = '\0'; snprintf(szResponse, sizeof(szResponse), "** CTCP %s %s %s", szTarget, szCTCPCmd + 1, szRemLine); return szResponse; } if (stricmp(szCTCPCmd + 1, "PING") == 0) { snprintf(szResponse, sizeof(szResponse), "/NOTICE %s :\001PING %s\001", szNick, szRemLine); // Don't need the trailing \001 because szremline has it. SendChatString(szResponse, 1); return nullptr; } if (stricmp(szCTCPCmd + 1, "VERSION") == 0) { // reply with a notice version & copyright // sprintf(szTempLine,"NOTICE %s :\001VERSION Copyright(c)\001\n",szNick); return nullptr; } strcpy(szRemLine, 1 + GetWordNum(0, Line + iPrefixLen + strlen(szCmd) + strlen(szTarget) + 4)); szRemLine[strlen(szRemLine) - 1] = '\0'; snprintf(szResponse, sizeof(szResponse), "** CTCP Message from %s (%s)", szNick, szRemLine); return nullptr; // szResponse; } // differentiate between channel and private if ((szTarget[0] == '#') || (szTarget[0] == '+')) { pszTempStr = GetWordNum(0, szRemLine); snprintf(szResponse, sizeof(szResponse), "\1\xff\xff\xff[%s] %s", szNick, pszTempStr); return szResponse; } else { if (iMode == MSG_LOCAL) { pszTempStr = GetWordNum(0, szRemLine); snprintf(szResponse, sizeof(szResponse), TXT_PXO_PRIVMSGTO, szTarget, pszTempStr); } else { pszTempStr = GetWordNum(0, szRemLine); snprintf(szResponse, sizeof(szResponse), TXT_PXO_PRIVMSGFROM, szNick, pszTempStr); } return szResponse; } } // don't handle any other messages locally. if (iMode == MSG_LOCAL) { return nullptr; } if (stricmp(szCmd, "NOTICE") == 0) { pszTempStr = GetWordNum(0, szRemLine); strcpy(szTarget, pszTempStr); strcpy(szRemLine, Line + iPrefixLen + strlen(szCmd) + strlen(szTarget) + 4); if (szRemLine[0] == ':') { strcpy(szCTCPCmd, GetWordNum(0, szRemLine + 1)); if (szCTCPCmd[strlen(szCTCPCmd) - 1] == 0x01) szCTCPCmd[strlen(szCTCPCmd) - 1] = 0x00; } else { strcpy(szCTCPCmd, GetWordNum(0, szRemLine)); if (szCTCPCmd[strlen(szCTCPCmd) - 1] == 0x01) szCTCPCmd[strlen(szCTCPCmd) - 1] = 0x00; } if (szCTCPCmd[0] == 0x01) { // Handle ctcp message strcpy(szRemLine, Line + iPrefixLen + strlen(szCmd) + strlen(szTarget) + strlen(szCTCPCmd) + 6); szRemLine[strlen(szRemLine) - 1] = '\0'; // null out the ending 0x01 if (stricmp(szCTCPCmd + 1, "PING") == 0) { // This is a ping response, figure out time and print // sprintf(NewMsg.Message,"** Ping Response from %s: %ums",szNick,ulping); return nullptr; } // Default message strcpy(szRemLine, 1 + GetWordNum(0, Line + iPrefixLen + strlen(szCmd) + strlen(szTarget) + 4)); szRemLine[strlen(szRemLine) - 1] = '\0'; snprintf(szResponse, sizeof(szResponse), "** CTCP Message from %s (%s)", szNick, szRemLine); return nullptr; // szResponse; } strncpy(szResponse, szRemLine, sizeof(szResponse)); return nullptr; } if (stricmp(szCmd, "JOIN") == 0) { // see if it is me! if (stricmp(Nick_name, szNick) == 0) { // Yup, it's me! // if(stricmp(szChat_channel,GetWordNum(0,szRemLine))==0) //{ Joined_channel = 1; // if(stricmp(szChat_channel,"#autoselect")==0) //{ strcpy(szChat_channel, GetWordNum(0, szRemLine)); AddChatCommandToQueue(CC_YOURCHANNEL, szChat_channel, strlen(szChat_channel) + 1); //} // CC_YOURCHANNEL //} } AddChatUser(szNick); pszTempStr = GetWordNum(0, szRemLine); strcpy(szTarget, pszTempStr); // strcpy(szRemLine,Line+iPrefixLen+strlen(szCmd)+strlen(szTarget)+3); // strcpy(NewMsg.Channel,szTarget); AddChatUser(szNick); snprintf(szResponse, sizeof(szResponse), "** %s has joined %s", szNick, szTarget); return nullptr; // szResponse; // Add them to the userlist too! } if (stricmp(szCmd, "PART") == 0) { pszTempStr = GetWordNum(0, szRemLine); strcpy(szTarget, pszTempStr); strcpy(szRemLine, Line + iPrefixLen + strlen(szCmd) + strlen(szTarget) + 3); // see if it is me! if (stricmp(Nick_name, szNick) == 0) { // Yup, it's me! // szChat_channel[0]=NULL; RemoveAllChatUsers(); } RemoveChatUser(szNick); return nullptr; // Remove them to the userlist too! } if (stricmp(szCmd, "KICK") == 0) { pszTempStr = GetWordNum(0, szRemLine); strcpy(szTarget, pszTempStr); pszTempStr = GetWordNum(1, szRemLine); strcpy(szHackPrefix, pszTempStr); pszTempStr = GetWordNum(2, szRemLine); // see if it is me! if (stricmp(Nick_name, GetWordNum(1, szRemLine)) == 0) { // Yup, it's me! szChat_channel[0] = '\0'; // bNewStatus=1; AddChatCommandToQueue(CC_KICKED, nullptr, 0); RemoveAllChatUsers(); } // sprintf(szResponse,"*** %s has kicked %s from channel %s (%s)",szNick,szHackPrefix,szTarget,pszTempStr); // Remove them to the userlist too! RemoveChatUser(szNick); return nullptr; // szResponse; } if (stricmp(szCmd, "NICK") == 0) { // see if it is me! if (stricmp(Nick_name, szNick) == 0) { // Yup, it's me! strcpy(Nick_name, GetWordNum(0, szRemLine)); } char nicks[70]; snprintf(nicks, sizeof(nicks), "%s %s", szNick, GetWordNum(0, szRemLine)); AddChatCommandToQueue(CC_NICKCHANGED, nicks, strlen(nicks) + 1); RemoveChatUser(szNick); AddChatUser(GetWordNum(0, szRemLine)); // sprintf(szResponse,"*** %s is now known as %s",szNick,GetWordNum(0,szRemLine)); return nullptr; // szResponse; } if (stricmp(szCmd, "PING") == 0) { // respond with pong (GetWordNum(0,szRemLine)) snprintf(szResponse, sizeof(szResponse), "/PONG :%s", GetWordNum(0, szRemLine)); SendChatString(szResponse, 1); return nullptr; } if (stricmp(szCmd, "MODE") == 0) { // Channel Mode info return nullptr; } if (stricmp(szCmd, "401") == 0) { // This is whois user info, we can get their tracker info from here. -5 char szWhoisUser[33]; strcpy(szWhoisUser, GetWordNum(1, szRemLine)); Getting_user_tracker_error = 1; Getting_user_channel_error = 1; snprintf(szResponse, sizeof(szResponse), TXT_PXO_ERRORNOTONLINE, szWhoisUser); return szResponse; } if (stricmp(szCmd, "311") == 0) { char szWhoisUser[33]; strcpy(szWhoisUser, GetWordNum(1, szRemLine)); // This is whois user info, we can get their tracker info from here. -5 // if(stricmp(Getting_user_tracker_info_for,szWhoisUser)==0) //{ strcpy(User_req_tracker_id, GetWordNum(5, szRemLine)); //} return nullptr; } if (stricmp(szCmd, "319") == 0) { char szWhoisUser[33]; strcpy(szWhoisUser, GetWordNum(1, szRemLine)); // This is whois channel info -- what channel they are on -2 // if(stricmp(Getting_user_channel_info_for,szWhoisUser)==0) //{ strcpy(User_req_channel, GetWordNum(2, szRemLine)); //} return nullptr; } // End of whois and we didn't get a channel means they aren't in a channel. if (stricmp(szCmd, "318") == 0) { if (!*User_req_channel) { User_req_channel[0] = '*'; } } if (stricmp(szCmd, "321") == 0) { // start of channel list FlushChannelList(); GettingChannelList = 1; return nullptr; } if (stricmp(szCmd, "322") == 0) { // channel list data if (GettingChannelList == 1) { char channel_list_name[33]; char sztopic[200]; strcpy(sztopic, GetWordNum(3, szRemLine)); strcpy(channel_list_name, GetWordNum(1, szRemLine)); AddChannel(channel_list_name, atoi(GetWordNum(2, szRemLine)), sztopic); } return nullptr; } if (stricmp(szCmd, "323") == 0) { // end of channel list GettingChannelList = 2; return nullptr; } if (stricmp(szCmd, "324") == 0) { // Channel Mode info return nullptr; } if (stricmp(szCmd, "332") == 0) { // Channel Topic, update status bar. if (stricmp(szChat_channel, szTarget) == 0) { // strncpy(szChanTopic,GetWordNum(2,szRemLine),70); } // sprintf(NewMsg.Message,"*** %s has changed the topic to: %s",szNick,GetWordNum(2,szRemLine)); return nullptr; } if (stricmp(szCmd, "TOPIC") == 0) { // Channel Topic, update status bar. if (stricmp(szChat_channel, szTarget) == 0) { // strncpy(szChanTopic,GetWordNum(1,szRemLine),70); } // sprintf(NewMsg.Message,"*** %s has changed the topic to: %s",szNick,GetWordNum(1,szRemLine)); return nullptr; } if (stricmp(szCmd, "QUIT") == 0) { // Remove the user! RemoveChatUser(szNick); return nullptr; } if (stricmp(szCmd, "376") == 0) // end of motd, trigger autojoin... { if (!Chat_server_connected) { DLLmprintf(0, "Connected to chat server!\n"); Chat_server_connected = 1; // We want to make sure we know our nick. This is somewhat of a hack strcpy(Nick_name, GetWordNum(0, szRemLine + 1)); } return nullptr; } if ((stricmp(szCmd, "377") == 0) || (stricmp(szCmd, "372") == 0) || (stricmp(szCmd, "372") == 0) ) { // Stip the message, and display it. pszTempStr = GetWordNum(3, Line); snprintf(szResponse, sizeof(szResponse), "\1\xcf\xf8\xb9%s", pszTempStr); return szResponse; } // Ignore these messages if (((stricmp(szCmd, "366") == 0)) || (stricmp(szCmd, "333") == 0) || // Who set the topic (stricmp(szCmd, "329") == 0)) // Time Channel created /* (stricmp(szCmd,"305")==0) || (stricmp(szCmd,"306")==0) || (stricmp(szCmd,"311")==0) || //WHOIS stuff (stricmp(szCmd,"312")==0) || (stricmp(szCmd,"313")==0) || (stricmp(szCmd,"317")==0) || (stricmp(szCmd,"318")==0) || (stricmp(szCmd,"319")==0) || */ { return nullptr; } if (stricmp(szCmd, "353") == 0) { // Names in the channel. pszTempStr = GetWordNum(3, Line + iPrefixLen + strlen(szCmd) + 2); strcpy(szRemLine, pszTempStr); pszTempStr = strtok(szRemLine, " "); while (pszTempStr) { if (pszTempStr[0] == '@') { AddChatUser(pszTempStr + 1); } else if (pszTempStr[0] == '+') { AddChatUser(pszTempStr + 1); } else { AddChatUser(pszTempStr); } pszTempStr = strtok(nullptr, " "); } return nullptr; } // MOTD Codes if ((stricmp(szCmd, "001") == 0) || (stricmp(szCmd, "002") == 0) || (stricmp(szCmd, "003") == 0) || (stricmp(szCmd, "004") == 0) || (stricmp(szCmd, "251") == 0) || (stricmp(szCmd, "254") == 0) || (stricmp(szCmd, "255") == 0) || (stricmp(szCmd, "265") == 0) || (stricmp(szCmd, "375") == 0) || (stricmp(szCmd, "372") == 0) || (stricmp(szCmd, "375") == 0)) { // Stip the message, and display it. pszTempStr = GetWordNum(3, Line); strcpy(szResponse, pszTempStr); return nullptr; // return szResponse; } if (stricmp(szCmd, "432") == 0) { // Channel Mode info snprintf(szResponse, sizeof(szResponse), "%s", TXT_PXO_BADNICK); AddChatCommandToQueue(CC_DISCONNECTED, nullptr, 0); return szResponse; } if (stricmp(szCmd, "433") == 0) { // Channel Mode info char new_nick[33]; snprintf(new_nick, sizeof(new_nick), "%s%d", Orignial_nick_name, Nick_variety); strcpy(Nick_name, new_nick); Nick_variety++; snprintf(szResponse, sizeof(szResponse), "/NICK %s", new_nick); SendChatString(szResponse, 1); return nullptr; } // Default print strcpy(szResponse, Line); // return szResponse; return nullptr; } void AddChatCommandToQueue(int command, const void *data, int len) { Currcommand = Firstcommand; if (Firstcommand == nullptr) { Firstcommand = (Chat_command *)DLLmem_malloc(sizeof(Chat_command)); // ASSERT(Firstcommand); Firstcommand->next = nullptr; Currcommand = Firstcommand; } else { while (Currcommand->next) { Currcommand = Currcommand->next; } Currcommand->next = (Chat_command *)DLLmem_malloc(sizeof(Chat_command)); // ASSERT(Currcommand->next); Currcommand = Currcommand->next; } Currcommand->command = command; if (len && data) memcpy(&Currcommand->data, data, len); Currcommand->next = nullptr; } Chat_command *GetChatCommandFromQueue() { static Chat_command response_cmd; Chat_command *tmp_cmd; if (!Firstcommand) return nullptr; Currcommand = Firstcommand; memcpy(&response_cmd, Currcommand, sizeof(Chat_command)); tmp_cmd = Currcommand->next; DLLmem_free(Firstcommand); Firstcommand = tmp_cmd; return &response_cmd; } void FlushChatCommandQueue() { Chat_command *tmp_cmd; Currcommand = Firstcommand; while (Currcommand) { tmp_cmd = Currcommand->next; DLLmem_free(Currcommand); Currcommand = tmp_cmd; } Firstcommand = nullptr; } void FlushChannelList() { Chat_channel *tmp_chan; Currchannel = Firstchannel; while (Currchannel) { tmp_chan = Currchannel->next; DLLmem_free(Currchannel); Currchannel = tmp_chan; } Firstchannel = nullptr; } char *GetChannelList() { int ichan_list_length = 0; char sznumusers[10]; if (GettingChannelList != 2) return nullptr; if (!Socket_connected) return nullptr; if (Chan_list) { DLLmem_free(Chan_list); Chan_list = nullptr; } Currchannel = Firstchannel; while (Currchannel) { ichan_list_length += strlen(Currchannel->topic) + 1 + strlen(Currchannel->channel_name) + 1 + 5; // 1 for the space, and 4 for the number of users 0000-9999 + space Currchannel = Currchannel->next; } Currchannel = Firstchannel; Chan_list = (char *)DLLmem_malloc(ichan_list_length + 1); Chan_list[0] = '\0'; while (Currchannel) { strcat(Chan_list, "$"); strcat(Chan_list, Currchannel->channel_name); strcat(Chan_list, " "); snprintf(sznumusers, sizeof(sznumusers), "%d ", Currchannel->users); strcat(Chan_list, sznumusers); strcat(Chan_list, Currchannel->topic); // fgets strcat(Chan_list, " "); Currchannel = Currchannel->next; } FlushChannelList(); GettingChannelList = 0; return Chan_list; } void AddChannel(char *channel, uint16_t numusers, char *topic) { Currchannel = Firstchannel; if (Firstchannel == nullptr) { Firstchannel = (Chat_channel *)DLLmem_malloc(sizeof(Chat_channel)); // ASSERT(Firstchannel); strcpy(Firstchannel->channel_name, channel); strcpy(Firstchannel->topic, topic); Firstchannel->users = numusers; Firstchannel->next = nullptr; Currchannel = Firstchannel; } else { while (Currchannel->next) { Currchannel = Currchannel->next; } Currchannel->next = (Chat_channel *)DLLmem_malloc(sizeof(Chat_channel)); // ASSERT(Currchannel->next); Currchannel = Currchannel->next; strcpy(Currchannel->channel_name, channel); strcpy(Currchannel->topic, topic); Currchannel->users = numusers; } Currchannel->next = nullptr; } char *GetTrackerIdByUser(const char *nickname) { char szWhoisCmd[100]; if (nickname == (char *)-1) { GettingUserTID = 0; Getting_user_tracker_error = 0; return nullptr; } else if (GettingUserTID) { if (Getting_user_tracker_error) { Getting_user_tracker_error = 0; GettingUserTID = 0; return (char *)-1; } if (*User_req_tracker_id) { GettingUserTID = 0; return User_req_tracker_id; } } else { strcpy(Getting_user_tracker_info_for, nickname); snprintf(szWhoisCmd, sizeof(szWhoisCmd), "/WHOIS %s", nickname); User_req_tracker_id[0] = '\0'; SendChatString(szWhoisCmd, 1); GettingUserTID = 1; } return nullptr; } char *GetChannelByUser(const char *nickname) { char szWhoisCmd[100]; if (nickname == (char *)-1) { GettingUserChannel = 0; Getting_user_channel_error = 0; return nullptr; } else if (GettingUserChannel) { if (Getting_user_channel_error) { Getting_user_channel_error = 0; GettingUserChannel = 0; return (char *)-1; } if (*User_req_channel) { GettingUserChannel = 0; return User_req_channel; } } else { strcpy(Getting_user_channel_info_for, nickname); User_req_channel[0] = '\0'; snprintf(szWhoisCmd, sizeof(szWhoisCmd), "/WHOIS %s", nickname); SendChatString(szWhoisCmd, 1); GettingUserChannel = 1; } return nullptr; }