diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1cd952b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,54 @@ +{ + "files.associations": { + "ostream": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "numbers": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "map": "cpp", + "sstream": "cpp" + } +} \ No newline at end of file diff --git a/Server.cpp b/Server.cpp index 03c1dfc..4d36b45 100644 --- a/Server.cpp +++ b/Server.cpp @@ -113,6 +113,157 @@ void Server::handleClientConnection() { } } + +// FUNCTIONS OF TOP GGGGGG.. START FROM HEEEREEE + + + + +std::string trim(const std::string& str) { + // Find the first non-whitespace character + size_t first = str.find_first_not_of(" \t\n\r"); + + // If the string is all whitespace, return an empty string + if (std::string::npos == first) { + return ""; + } + + // Find the last non-whitespace character + size_t last = str.find_last_not_of(" \t\n\r"); + + // Return the trimmed substring + return str.substr(first, last - first + 1); +} + +void Server::createChannel(const std::string& channelName, const std::string& nickname) { + // Check if the channel already exists + if (channels.find(channelName) == channels.end()) { + // Channel doesn't exist, so create it + std::vector users; + users.push_back(nickname); // Add the user to the channel + channels[channelName] = users; + std::cout << "Channel '" << channelName << "' created by '" << nickname << "'" << std::endl; + } else { + // Channel already exists, just add the user to it + channels[channelName].push_back(nickname); + std::cout << "User '" << nickname << "' joined channel '" << channelName << "'" << std::endl; + } +} + +bool startsWith(const std::string& str, const std::string& prefix) { + return str.substr(0, prefix.length()) == prefix; +} + + void Server::setNickname(int fd, const std::string& nickname) { + nicknames[fd] = nickname; // Associate the nickname with the client's socket descriptor + } + + void Server::setUsername(int fd, const std::string& username) { + usernames[fd] = username; // Associate the nickname with the client's socket descriptor + } + +void sendResponse(int fd, const std::string& message) { + // Convert the message string to a C-style string + const char* msg = message.c_str(); + + // Get the length of the message + size_t len = strlen(msg); + + // Send the message to the client + ssize_t bytesSent = send(fd, msg, len, 0); + + // Check if the send operation was successful + if (bytesSent == -1) { + // Handle send error + // You can log an error message or take appropriate action + std::cerr << "Error sending response to client <" << fd << ">" << std::endl; + } else { + // Output the sent message to the console + std::cout << "Response sent to client <" << fd << ">: " << message << std::endl; + } + } + + + +int findUserFd(const std::string& nickname, const std::map& usernames) { + // Iterate over each entry in the usernames map + for (std::map::const_iterator it = usernames.begin(); it != usernames.end(); ++it) { + // Check if the nickname matches + if (it->second == nickname) { + // Return the file descriptor associated with the nickname + return it->first; + } + } + // Return -1 if the nickname is not found + return -1; +} + + + +void Server::handlePrivateMessage(int senderFd, const std::string& recipient, const std::string& message) { + // Find the recipient's connection (socket file descriptor) + int recipientFd = findUserFd(recipient, usernames); + + if (recipientFd != -1) { + // Forward the private message to the recipient's client + std::string privateMessage = "PRIVATE " + usernames[senderFd] + ": " + message + "\n"; + send(recipientFd, privateMessage.c_str(), privateMessage.length(), 0); + } else { + // Handle case where recipient is not found (e.g., user not online) + std::string errorMessage = "Error: User '" + recipient + "' not found or offline\n"; + send(senderFd, errorMessage.c_str(), errorMessage.length(), 0); + } +} + +int Server::findUserFd1(const std::string& nickname) { + std::map::iterator it; + for (it = nicknames.begin(); it != nicknames.end(); ++it) { + if (it->second == nickname) { + return it->first; // Return the file descriptor if the nickname matches + } + } + return -1; // Return -1 if the nickname is not found +} + +void Server::broadcastMessage(const std::string& channel, const std::string& senderNickname, const std::string& msg) { + // Check if the channel exists + if (channels.find(channel) == channels.end()) { + std::cerr << "Channel " << channel << " does not exist" << std::endl; + return; + } + + // Iterate through all clients in the channel and send the message +// Get a reference to the vector of clients in the channel + const std::vector& clients = channels[channel]; + + // Iterate over the vector using iterators + std::vector::const_iterator it; + for (it = clients.begin(); it != clients.end(); ++it) { + // Get the current client nickname + const std::string& client = *it; + + // Find the file descriptor associated with the client nickname + int recipientFd = findUserFd1(client); + + // If the file descriptor is found, send the message to the client + if (recipientFd != -1) { + std::string message = "PRIVMSG " + channel + " :" + senderNickname + ": " + msg + "\r\n"; + send(recipientFd, message.c_str(), message.size(), 0); + } else { + // If the file descriptor is not found, print an error message + std::cerr << "Client " << client << " not found" << std::endl; + } + } +} + + + + + + +// ........AND FINISH HERE ......////// + + void Server::handleClientData(int fd) { std::string command; char buffer[BUFFER_SIZE]; @@ -134,7 +285,69 @@ void Server::handleClientData(int fd) { } else { command.append(buffer, bytesRead - 1); std::cout << "Received data from client " << fd << ": " << command << std::endl; - // process the command here + +//******************* FROM THERE IM STARTING TOP GGG ************ . + if (startsWith(command, "/setnick ")) { + // Extract the nickname from the command + std::string nickname = command.substr(9); // Assuming "/setnick " is 9 characters long + + // Handle setting the nickname for the client's connection + setNickname(fd, nickname); + + // Send a response back to the client confirming the action + sendResponse(fd, "Nickname set to: " + nickname); + } else if (startsWith(command, "/setuser ")) { + std::string username = command.substr(9); + + setUsername(fd, username); + + sendResponse(fd, "Username set to: " + username); + + // Process other commands or messages + // processCommand(fd, command); + } else if (startsWith(command, "/join ")) { + std::string chanelname = command.substr(5); + chanelname = trim(chanelname); + createChannel(chanelname, nicknames[fd]); + + } else if (startsWith(command, "PRIVMSG ")) { + // Extract the recipient and the message from the command + std::istringstream iss(command); + std::string cmd, recipient, message; + iss >> cmd >> recipient; + recipient = trim(recipient); + std::getline(iss, message); + message = trim(message); + if (recipient[0] == '#') + { + recipient = recipient.substr(1); + std::cout << "this the chanel name and was good : " << recipient << std::endl; + broadcastMessage(recipient, nicknames[fd], message); + } + else + { + if (message[0] == ':') { + message = message.substr(1); + handlePrivateMessage(fd, recipient, message); + } + + } + // Remove the colon from the recipient if present + // if (!recipient.empty() && recipient[1] == ':') { + // recipient = recipient.substr(1); + // } + + + // Read the rest of the line as the message + + // if (message[0] == ':') + // message = message.substr(1); + + // Print the extracted recipient and message for debugging + std::cout << "Recipient: " << recipient << std::endl; + std::cout << "Message: " << message << std::endl; + } +//**************** STOOOOOOP HERE TOP G ... break; } } @@ -148,6 +361,7 @@ void Server::handleClientData(int fd) { } } + void Server::clientCleanup(int fd) { for (std::vector::iterator it = _fds.begin(); it != _fds.end(); ++it) { if (it->fd == fd) { diff --git a/Server.hpp b/Server.hpp index ffd3669..e79a2ca 100644 --- a/Server.hpp +++ b/Server.hpp @@ -1,6 +1,11 @@ #ifndef SERVER_HPP #define SERVER_HPP +#include +#include +#include +#include // Include for the send function +#include // Include for the strlen function #include #include #include @@ -10,8 +15,10 @@ #include #include "Client.hpp" #include +#include #define BUFFER_SIZE 1024 + class Server { private: int _port; @@ -20,10 +27,24 @@ class Server { std::string _password; std::vector _fds; std::vector _clients; + // THAT'S THA DATA OF TOOOP GGG START FROM THERE . + std::map nicknames; // Replace unordered_map with map + std::map usernames; // Replace unordered_map with map + std::map > channels; //here a chanel name and list of client in every chanel + + + public: Server(); ~Server(); - + // THAT'S MY FUNCTIONS START FROM THERE + void setNickname(int fd, const std::string& nickname); + void setUsername(int fd, const std::string& username); + void createChannel(const std::string& channel, const std::string& nickname); + void handlePrivateMessage(int senderFd, const std::string& recipient, const std::string& message); + void broadcastMessage(const std::string& channel, const std::string& senderNickname, const std::string& msg); + int findUserFd1(const std::string& nickname); + // AND END HERE. void parseArgs(int ac, char **av); static void receiveSignal(int signum); void init();