#include "IrcParser.hpp" #include IrcParser::IrcParser(void) {} IrcParser::IrcParser(const IrcParser &other) { (void)other; } IrcParser &IrcParser::operator=(const IrcParser &other) { (void)other; return (*this); } IrcParser::~IrcParser(void) {} bool IrcParser::isSpace(char c) { return (c == ' ' || c == '\t'); } std::string IrcParser::trimLeft(const std::string &s) { size_t i = 0; while (i < s.size() && isSpace(s[i])) i++; return (s.substr(i)); } std::string IrcParser::trimRight(const std::string &s) { size_t end = s.size(); while (end > 0 && (s[end - 1] == '\r' || s[end - 1] == '\n' || isSpace(s[end - 1]))) end--; return (s.substr(0, end)); } std::string IrcParser::toUpper(const std::string &s) { std::string out = s; for (size_t i = 0; i < out.size(); ++i) out[i] = static_cast(std::toupper(static_cast(out[i]))); return (out); } bool IrcParser::isCommandChar(char c) { return (std::isalpha(static_cast(c)) || std::isdigit(static_cast(c))); } bool IrcParser::isValidCommand(const std::string &command) { if (command.empty()) return (false); for (size_t i = 0; i < command.size(); ++i) { if (!isCommandChar(command[i])) return (false); } return (true); } /* IRC params rule: - parameters are separated by spaces - if a parameter starts with ':', it is the trailing parameter - the trailing parameter may contain spaces and is always the last param Example: PRIVMSG #chan :hello les gars params[0] = "#chan" params[1] = "hello les gars" */ void IrcParser::parseParams(const std::string &s, size_t pos, IrcMessage &msg) { while (pos < s.size()) { while (pos < s.size() && isSpace(s[pos])) pos++; if (pos >= s.size()) break; if (s[pos] == ':') { msg.addParam(s.substr(pos + 1)); break; } size_t start = pos; while (pos < s.size() && !isSpace(s[pos])) pos++; msg.addParam(s.substr(start, pos - start)); } } IrcMessage IrcParser::parseLine(const std::string &line) { IrcMessage msg; std::string s; size_t pos; size_t start; msg.setRaw(line); s = trimRight(trimLeft(line)); if (s.empty()) { msg.setError("empty line"); return (msg); } /* Optional prefix: :nick!user@host COMMAND params... In ft_irc, clients usually do not send prefixes, but accepting it makes the parser robust. */ pos = 0; if (s[pos] == ':') { size_t prefixEnd = s.find(' ', pos); if (prefixEnd == std::string::npos) { msg.setError("prefix without command"); return (msg); } msg.setPrefix(s.substr(1, prefixEnd - 1)); pos = prefixEnd + 1; while (pos < s.size() && isSpace(s[pos])) pos++; } start = pos; while (pos < s.size() && !isSpace(s[pos])) pos++; msg.setCommand(toUpper(s.substr(start, pos - start))); if (!isValidCommand(msg.getCommand())) { msg.setError("invalid command"); return (msg); } parseParams(s, pos, msg); msg.setValid(true); return (msg); }