Added nick hilight support to the IRC client

This commit is contained in:
Dionysus 2024-05-25 23:39:20 -04:00
parent 259f0ca443
commit 2cb5b2ccae
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
2 changed files with 169 additions and 151 deletions

View File

@ -35,8 +35,9 @@ This is being developed in my free time as a fun project. It is no where near be
- [X] Wifi scanning & selection menu - [X] Wifi scanning & selection menu
- [ ] Saved wifi profiles - [ ] Saved wifi profiles
- [X] IRC Client - [X] IRC Client
- [X] `/raw` command for IRC client to send raw data to the server - [X] `/raw` command for IRC client to send raw data to the server
- [ ] Add scrolling backlog for IRC to see the last 200 messages - [ ] Add scrolling backlog for IRC to see the last 200 messages
- [X] Hilight support *(so we can see when people mention our NICK)*
- [ ] ChatGPT - [ ] ChatGPT
- [ ] SSH Client - [ ] SSH Client
- [ ] Wardriving - [ ] Wardriving

View File

@ -30,6 +30,7 @@ WiFiClientSecure client;
std::map<String, uint32_t> nickColors; std::map<String, uint32_t> nickColors;
std::vector<String> lines; std::vector<String> lines;
std::vector<bool> mentions;
String inputBuffer = ""; String inputBuffer = "";
// WiFi credentials // WiFi credentials
@ -88,6 +89,158 @@ void setup() {
nick = "ACID_" + String(randomNum); nick = "ACID_" + String(randomNum);
} }
void displayLines() {
tft.fillRect(0, STATUS_BAR_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - STATUS_BAR_HEIGHT - INPUT_LINE_HEIGHT, TFT_BLACK);
int cursorY = STATUS_BAR_HEIGHT;
for (size_t i = 0; i < lines.size(); ++i) {
const String& line = lines[i];
bool mention = mentions[i];
tft.setCursor(0, cursorY);
if (line.startsWith("JOIN ")) {
tft.setTextColor(TFT_GREEN);
tft.print("JOIN ");
int startIndex = 5;
int endIndex = line.indexOf(" has joined ");
String senderNick = line.substring(startIndex, endIndex);
tft.setTextColor(nickColors[senderNick]);
tft.print(senderNick);
tft.setTextColor(TFT_WHITE);
tft.print(" has joined ");
tft.setTextColor(TFT_CYAN);
tft.print(channel);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("PART ")) {
tft.setTextColor(TFT_RED);
tft.print("PART ");
int startIndex = 5;
int endIndex = line.indexOf(" has EMO-QUIT ");
String senderNick = line.substring(startIndex, endIndex);
tft.setTextColor(nickColors[senderNick]);
tft.print(senderNick);
tft.setTextColor(TFT_WHITE);
tft.print(" has EMO-QUIT ");
tft.setTextColor(TFT_CYAN);
tft.print(channel);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("QUIT ")) {
tft.setTextColor(TFT_RED);
tft.print("QUIT ");
String senderNick = line.substring(5);
tft.setTextColor(nickColors[senderNick]);
tft.print(senderNick);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("NICK ")) {
tft.setTextColor(TFT_BLUE);
tft.print("NICK ");
int startIndex = 5;
int endIndex = line.indexOf(" -> ");
String oldNick = line.substring(startIndex, endIndex);
String newNick = line.substring(endIndex + 4);
tft.setTextColor(nickColors[oldNick]);
tft.print(oldNick);
tft.setTextColor(TFT_WHITE);
tft.print(" -> ");
tft.setTextColor(nickColors[newNick]);
tft.print(newNick);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("KICK ")) {
tft.setTextColor(TFT_RED);
tft.print("KICK ");
int startIndex = 5;
int endIndex = line.indexOf(" by ");
String kickedNick = line.substring(startIndex, endIndex);
String kicker = line.substring(endIndex + 4);
tft.setTextColor(nickColors[kickedNick]);
tft.print(kickedNick);
tft.setTextColor(TFT_WHITE);
tft.print(" by ");
tft.setTextColor(nickColors[kicker]);
tft.print(kicker);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("MODE ")) {
tft.setTextColor(TFT_BLUE);
tft.print("MODE ");
String modeChange = line.substring(5);
tft.setTextColor(TFT_WHITE);
tft.print(modeChange);
cursorY += CHAR_HEIGHT;
} else {
int colonPos = line.indexOf(':');
String senderNick = line.substring(0, colonPos);
String message = line.substring(colonPos + 2);
tft.setTextColor(nickColors[senderNick]);
tft.print(senderNick + ": ");
tft.setTextColor(TFT_WHITE);
// Check if the message contains the nick and highlight it
int nickPos = message.indexOf(nick);
if (mention && nickPos != -1) {
// Print part before the nick
tft.print(message.substring(0, nickPos));
// Print the nick in yellow
tft.setTextColor(TFT_YELLOW);
tft.print(nick);
// Print the part after the nick
tft.setTextColor(TFT_WHITE);
tft.print(message.substring(nickPos + nick.length()));
cursorY += CHAR_HEIGHT; // Ensure cursor moves to the next line after the highlighted message
} else {
cursorY = renderFormattedMessage(message, cursorY, CHAR_HEIGHT);
}
}
}
displayInputLine();
}
void addLine(String senderNick, String message, String type, bool mention = false) {
if (nickColors.find(senderNick) == nickColors.end())
nickColors[senderNick] = generateRandomColor();
String formattedMessage;
if (type == "join") {
formattedMessage = "JOIN " + senderNick + " has joined " + String(channel);
} else if (type == "part") {
formattedMessage = "PART " + senderNick + " has EMO-QUIT " + String(channel);
} else if (type == "quit") {
formattedMessage = "QUIT " + senderNick;
} else if (type == "nick") {
int arrowPos = message.indexOf(" -> ");
String oldNick = senderNick;
String newNick = message.substring(arrowPos + 4);
if (nickColors.find(newNick) == nickColors.end()) {
nickColors[newNick] = generateRandomColor();
}
formattedMessage = "NICK " + oldNick + " -> " + newNick;
} else if (type == "kick") {
formattedMessage = "KICK " + senderNick + message;
} else if (type == "mode") {
formattedMessage = "MODE " + message;
} else {
formattedMessage = senderNick + ": " + message;
}
int linesRequired = calculateLinesRequired(formattedMessage);
while (lines.size() + linesRequired > MAX_LINES) {
lines.erase(lines.begin());
mentions.erase(mentions.begin());
}
lines.push_back(formattedMessage);
mentions.push_back(mention);
displayLines();
}
void loop() { void loop() {
if (ssid.isEmpty()) { if (ssid.isEmpty()) {
char incoming = getKeyboardInput(); char incoming = getKeyboardInput();
@ -133,8 +286,6 @@ void loop() {
} }
} }
bool connectToIRC() { bool connectToIRC() {
if (useSSL) { if (useSSL) {
client.setInsecure(); client.setInsecure();
@ -145,7 +296,6 @@ bool connectToIRC() {
} }
} }
void connectToWiFi() { void connectToWiFi() {
WiFi.begin(ssid.c_str(), password.c_str()); WiFi.begin(ssid.c_str(), password.c_str());
@ -158,7 +308,6 @@ void connectToWiFi() {
updateTimeFromNTP(); updateTimeFromNTP();
} }
void sendIRC(String command) { void sendIRC(String command) {
if (client.println(command)) if (client.println(command))
Serial.println(">>> " + command); Serial.println(">>> " + command);
@ -209,18 +358,19 @@ void parseAndDisplay(String line) {
if (target == String(channel)) { if (target == String(channel)) {
int colonPos = line.indexOf(':', thirdSpace); int colonPos = line.indexOf(':', thirdSpace);
String message = line.substring(colonPos + 1); String message = line.substring(colonPos + 1);
String nick = line.substring(1, line.indexOf('!')); String senderNick = line.substring(1, line.indexOf('!'));
addLine(nick, message, "message"); bool mention = message.indexOf(nick) != -1;
addLine(senderNick, message, "message", mention);
} }
} else if (command == "JOIN" && line.indexOf(channel) != -1) { } else if (command == "JOIN" && line.indexOf(channel) != -1) {
String nick = line.substring(1, line.indexOf('!')); String senderNick = line.substring(1, line.indexOf('!'));
addLine(nick, " has joined " + String(channel), "join"); addLine(senderNick, " has joined " + String(channel), "join");
} else if (command == "PART" && line.indexOf(channel) != -1) { } else if (command == "PART" && line.indexOf(channel) != -1) {
String nick = line.substring(1, line.indexOf('!')); String senderNick = line.substring(1, line.indexOf('!'));
addLine(nick, " has EMO-QUIT " + String(channel), "part"); addLine(senderNick, " has EMO-QUIT " + String(channel), "part");
} else if (command == "QUIT" && line.indexOf(channel) != -1) { } else if (command == "QUIT" && line.indexOf(channel) != -1) {
String nick = line.substring(1, line.indexOf('!')); String senderNick = line.substring(1, line.indexOf('!'));
addLine(nick, "", "quit"); addLine(senderNick, "", "quit");
} else if (command == "NICK") { } else if (command == "NICK") {
String oldNick = line.substring(1, line.indexOf('!')); String oldNick = line.substring(1, line.indexOf('!'));
String newNick = line.substring(line.lastIndexOf(':') + 1); String newNick = line.substring(line.lastIndexOf(':') + 1);
@ -305,133 +455,6 @@ void displayCenteredText(String text) {
tft.drawString(text, SCREEN_WIDTH / 2, (SCREEN_HEIGHT + STATUS_BAR_HEIGHT) / 2); tft.drawString(text, SCREEN_WIDTH / 2, (SCREEN_HEIGHT + STATUS_BAR_HEIGHT) / 2);
} }
void addLine(String nick, String message, String type) {
if (nickColors.find(nick) == nickColors.end())
nickColors[nick] = generateRandomColor();
String formattedMessage;
if (type == "join") {
formattedMessage = "JOIN " + nick + " has joined " + String(channel);
} else if (type == "part") {
formattedMessage = "PART " + nick + " has EMO-QUIT " + String(channel);
} else if (type == "quit") {
formattedMessage = "QUIT " + nick;
} else if (type == "nick") {
int arrowPos = message.indexOf(" -> ");
String oldNick = nick;
String newNick = message.substring(arrowPos + 4);
if (nickColors.find(newNick) == nickColors.end()) {
nickColors[newNick] = generateRandomColor();
}
formattedMessage = "NICK " + oldNick + " -> " + newNick;
} else if (type == "kick") {
formattedMessage = "KICK " + nick + message;
} else if (type == "mode") {
formattedMessage = "MODE " + message;
} else {
formattedMessage = nick + ": " + message;
}
int linesRequired = calculateLinesRequired(formattedMessage);
while (lines.size() + linesRequired > MAX_LINES)
lines.erase(lines.begin());
lines.push_back(formattedMessage);
displayLines();
}
void displayLines() {
tft.fillRect(0, STATUS_BAR_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - STATUS_BAR_HEIGHT - INPUT_LINE_HEIGHT, TFT_BLACK);
int cursorY = STATUS_BAR_HEIGHT;
for (const String& line : lines) {
tft.setCursor(0, cursorY);
if (line.startsWith("JOIN ")) {
tft.setTextColor(TFT_GREEN);
tft.print("JOIN ");
int startIndex = 5;
int endIndex = line.indexOf(" has joined ");
String nick = line.substring(startIndex, endIndex);
tft.setTextColor(nickColors[nick]);
tft.print(nick);
tft.setTextColor(TFT_WHITE);
tft.print(" has joined ");
tft.setTextColor(TFT_CYAN);
tft.print(channel);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("PART ")) {
tft.setTextColor(TFT_RED);
tft.print("PART ");
int startIndex = 5;
int endIndex = line.indexOf(" has EMO-QUIT ");
String nick = line.substring(startIndex, endIndex);
tft.setTextColor(nickColors[nick]);
tft.print(nick);
tft.setTextColor(TFT_WHITE);
tft.print(" has EMO-QUIT ");
tft.setTextColor(TFT_CYAN);
tft.print(channel);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("QUIT ")) {
tft.setTextColor(TFT_RED);
tft.print("QUIT ");
String nick = line.substring(5);
tft.setTextColor(nickColors[nick]);
tft.print(nick);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("NICK ")) {
tft.setTextColor(TFT_BLUE);
tft.print("NICK ");
int startIndex = 5;
int endIndex = line.indexOf(" -> ");
String oldNick = line.substring(startIndex, endIndex);
String newNick = line.substring(endIndex + 4);
tft.setTextColor(nickColors[oldNick]);
tft.print(oldNick);
tft.setTextColor(TFT_WHITE);
tft.print(" -> ");
tft.setTextColor(nickColors[newNick]);
tft.print(newNick);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("KICK ")) {
tft.setTextColor(TFT_RED);
tft.print("KICK ");
int startIndex = 5;
int endIndex = line.indexOf(" by ");
String kickedNick = line.substring(startIndex, endIndex);
String kicker = line.substring(endIndex + 4);
tft.setTextColor(nickColors[kickedNick]);
tft.print(kickedNick);
tft.setTextColor(TFT_WHITE);
tft.print(" by ");
tft.setTextColor(nickColors[kicker]);
tft.print(kicker);
cursorY += CHAR_HEIGHT;
} else if (line.startsWith("MODE ")) {
tft.setTextColor(TFT_BLUE);
tft.print("MODE ");
String modeChange = line.substring(5);
tft.setTextColor(TFT_WHITE);
tft.print(modeChange);
cursorY += CHAR_HEIGHT;
} else {
int colonPos = line.indexOf(':');
String nick = line.substring(0, colonPos);
String message = line.substring(colonPos + 2);
tft.setTextColor(nickColors[nick]);
tft.print(nick + ": ");
tft.setTextColor(TFT_WHITE);
cursorY = renderFormattedMessage(message, cursorY, CHAR_HEIGHT);
}
}
displayInputLine();
}
int renderFormattedMessage(String message, int cursorY, int lineHeight) { int renderFormattedMessage(String message, int cursorY, int lineHeight) {
uint16_t fgColor = TFT_WHITE; uint16_t fgColor = TFT_WHITE;
uint16_t bgColor = TFT_BLACK; uint16_t bgColor = TFT_BLACK;
@ -497,6 +520,7 @@ int renderFormattedMessage(String message, int cursorY, int lineHeight) {
return cursorY; // Return the new cursor Y position for the next line return cursorY; // Return the new cursor Y position for the next line
} }
int calculateLinesRequired(String message) { int calculateLinesRequired(String message) {
int linesRequired = 1; int linesRequired = 1;
int lineWidth = 0; int lineWidth = 0;
@ -562,8 +586,6 @@ void displayPasswordInputLine() {
tft.print("> " + inputBuffer); tft.print("> " + inputBuffer);
} }
void updateSelectedNetwork(int delta) { void updateSelectedNetwork(int delta) {
int newIndex = selectedNetworkIndex + delta; int newIndex = selectedNetworkIndex + delta;
if (newIndex >= 0 && newIndex < wifiNetworks.size()) { if (newIndex >= 0 && newIndex < wifiNetworks.size()) {
@ -602,8 +624,6 @@ void displayWiFiNetworks() {
} }
} }
void displayWiFiNetwork(int index, int displayIndex) { void displayWiFiNetwork(int index, int displayIndex) {
int y = STATUS_BAR_HEIGHT + displayIndex * (CHAR_HEIGHT + LINE_SPACING); int y = STATUS_BAR_HEIGHT + displayIndex * (CHAR_HEIGHT + LINE_SPACING);
tft.setCursor(0, y); tft.setCursor(0, y);
@ -625,8 +645,6 @@ void displayWiFiNetwork(int index, int displayIndex) {
tft.printf("%-8s %s", net.encryption.c_str(), net.ssid.c_str()); tft.printf("%-8s %s", net.encryption.c_str(), net.ssid.c_str());
} }
void handleWiFiSelection(char key) { void handleWiFiSelection(char key) {
if (key == 'u') { if (key == 'u') {
updateSelectedNetwork(-1); updateSelectedNetwork(-1);
@ -706,7 +724,7 @@ void updateStatusBar() {
tft.setTextColor(TFT_PINK, darkerGrey); tft.setTextColor(TFT_PINK, darkerGrey);
tft.drawString("WiFi:", SCREEN_WIDTH - 120, STATUS_BAR_HEIGHT / 2); tft.drawString("WiFi:", SCREEN_WIDTH - 120, STATUS_BAR_HEIGHT / 2);
tft.setTextColor(getColorFromPercentage(wifiSignal), darkerGrey); tft.setTextColor(getColorFromPercentage(wifiSignal), darkerGrey);
tft.drawString(wifiStr + 6, SCREEN_WIDTH - 100, STATUS_BAR_HEIGHT / 2); // +6 to skip "WiFi: " tft.drawString(wifiStr + 6, SCREEN_WIDTH - 100, STATUS_BAR_HEIGHT / 2);
} }
int batteryLevel = BL.getBatteryChargeLevel(); int batteryLevel = BL.getBatteryChargeLevel();
@ -716,7 +734,7 @@ void updateStatusBar() {
tft.setTextColor(TFT_CYAN, darkerGrey); tft.setTextColor(TFT_CYAN, darkerGrey);
tft.drawString("Batt:", SCREEN_WIDTH - 40, STATUS_BAR_HEIGHT / 2); tft.drawString("Batt:", SCREEN_WIDTH - 40, STATUS_BAR_HEIGHT / 2);
tft.setTextColor(getColorFromPercentage(batteryLevel), darkerGrey); tft.setTextColor(getColorFromPercentage(batteryLevel), darkerGrey);
tft.drawString(batteryStr + 5, SCREEN_WIDTH - 5, STATUS_BAR_HEIGHT / 2); // +5 to skip "Batt: " tft.drawString(batteryStr + 5, SCREEN_WIDTH - 5, STATUS_BAR_HEIGHT / 2);
} }
uint16_t getColorFromPercentage(int rssi) { uint16_t getColorFromPercentage(int rssi) {
@ -726,10 +744,9 @@ uint16_t getColorFromPercentage(int rssi) {
else return TFT_RED; else return TFT_RED;
} }
void updateTimeFromNTP() { void updateTimeFromNTP() {
configTime(-5 * 3600, 0, "pool.ntp.org", "time.nist.gov"); configTime(-5 * 3600, 0, "pool.ntp.org", "time.nist.gov");
delay(2000); // Wait for NTP to sync delay(2000);
struct tm timeinfo; struct tm timeinfo;
if (getLocalTime(&timeinfo)) { if (getLocalTime(&timeinfo)) {
Serial.println(&timeinfo, "Time synchronized: %A, %B %d %Y %H:%M:%S"); Serial.println(&timeinfo, "Time synchronized: %A, %B %d %Y %H:%M:%S");