/* * This file is part of blabouncer (https://www.blatech.co.uk/l_bratch/blabouncer). * Copyright (C) 2019 Luke Bratch . * * Blabouncer 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, version 3. * * Blabouncer 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 blabouncer. If not, see . */ #include "functions.h" // Global debug control extern int debug; extern char debugpath[PATH_MAX]; extern int background; // Internal function just to replace nick in server greeting strings // (as in ":servername 00x oldnick :Blablabla" -> ":servername 00x newnick :Blablabla") void updategreetingnick(char *greeting, char *greetingnum, char *newnick, char *oldnick) { debugprint(DEBUG_FULL, "updategreetingnick(): '%s' '%s' '%s' '%s'.\n", greeting, greetingnum, newnick, oldnick); // Find the position of the old nick in the current greeting char searchstr[MAXDATASIZE]; snprintf(searchstr, MAXDATASIZE, " %s %s :", greetingnum, oldnick); char *ret; ret = strstr(greeting, searchstr); // If ret not found, try again without the colon (e.g. for greeting 004) if (ret == NULL) { snprintf(searchstr, MAXDATASIZE, " %s %s ", greetingnum, oldnick); ret = strstr(greeting, searchstr); } // Perhaps the new nick is already present (seen for instance when connecting to another bouncer like Miau) if (ret == NULL) { snprintf(searchstr, MAXDATASIZE, " %s %s ", greetingnum, newnick); ret = strstr(greeting, searchstr); if (ret != NULL) { debugprint(DEBUG_FULL, "updategreetingnick(): newnick is already present, returning.\n"); return; } } // If ret *still* not found, abandon ship if (ret == NULL) { debugprint(DEBUG_CRIT, "Error updating greeting string, substring not found. Exiting!\n"); printf("Error updating greeting string, substring not found. Exiting!\n"); exit(1); } int pos = ret - greeting + 5; // +5 for " 001 " // Copy the start of the old greeting into a new string char greetingtmp[MAXDATASIZE]; strncpy(greetingtmp, greeting, pos); // Terminate it greetingtmp[pos] = '\0'; // Now smash everything (start of old greeting + new nick + remainder of old greeting) // together into the new greeting, put in a new temporary string char greetingtmp2[MAXDATASIZE]; if (!snprintf(greetingtmp2, MAXDATASIZE, "%s%s %s", greetingtmp, newnick, greeting + pos + strlen(oldnick) + 1)) { fprintf(stderr, "Error while preparing new greeting string!\n"); debugprint(DEBUG_CRIT, "Error while preparing new greeting string!\n"); exit(1); } // And finally copy back to source string strcpy(greeting, greetingtmp2); debugprint(DEBUG_FULL, "updategreetingnick(): Built new greeting '%s' '%s', length '%ld'.\n", greetingnum, greeting, strlen(greeting)); } // Write debug string to file. // Debug level is provided by level, set to one of DEBUG_CRIT, DEBUG_SOME or DEBUG_FULL. // Debug is only written if the global int "debug" is greater than or equal to the level. void debugprint(int level, char *format, ...) { // Stop here if the user's debug level is less than the level of the current message if (debug < level) return; if (strlen(debugpath) < 1) { // debugpath isn't set, we can't do anything here return; } va_list args; va_start(args, format); FILE *fp; int bytes = 0; fp = fopen(debugpath, "a"); if (fp == NULL) { printf("Couldn't open debugpath '%s'!\n", debugpath); return; } if ((bytes = vfprintf(fp, format, args)) < 0) { debugprint(DEBUG_CRIT, "error: could not write to debug file.\n"); } fclose(fp); va_end(args); } // Get stdin line with buffer overrun protection int getstdin(char *prompt, char *buff, size_t sz) { int ch, extra; // Print optional prompt if (prompt != NULL) { printf ("%s", prompt); fflush (stdout); } // Get the intput from stdin if (fgets (buff, sz, stdin) == NULL) { return NO_INPUT; } // If it was too long, there'll be no newline. In that case, we flush // to end of line so that excess doesn't affect the next call. if (buff[strlen(buff) - 1] != '\n') { // strlen of the actually entered line, not the original array size extra = 0; while (((ch = getchar()) != '\n') && (ch != EOF)) { extra = 1; } return (extra == 1) ? TOO_LONG : OK; } // Otherwise remove newline and give string back to caller. buff[strlen(buff) - 1] = '\0'; return OK; } // Append CR-LF to the end of a string (after cleaning up any existing trailing CR or LF) void appendcrlf(char *string) { // Make sure it doesn't already end with CR or LF // (But only if string is at least two characters long already) if (strlen(string) >= 2) { while (string[strlen(string) - 1] == '\r' || string[strlen(string) - 1] == '\n') { string[strlen(string) - 1] = '\0'; } } int startlen = strlen(string); string[startlen] = '\r'; // Add CR string[startlen + 1] = '\n'; // Add LF string[startlen + 2] = '\0'; // Finish with null terminator } // Remove leading colon ':' which is the starting character of a prefix in an IRC message void stripprefix(char *string) { // Make a copy to work with char string2[strlen(string)]; debugprint(DEBUG_FULL, "stripprefix(): starting with '%s', strlen: %zd.\n", string, strlen(string)); // Don't bother if this isn't a prefix with a leading ':' if (string[0] != ':') { debugprint(DEBUG_FULL, "stripprefix(): no leading ':', returning.\n"); return; } // Copy the old string into a new one, but... for (size_t i = 1; i < strlen(string); i++) { string2[i - 1] = string[i]; } // Copy result back to original string strncpy(string, string2, strlen(string) - 1); // Finish with null terminator string[strlen(string) - 1] = '\0'; debugprint(DEBUG_FULL, "stripprefix(): finishing with '%s', strlen: %zd.\n", string, strlen(string)); } // Extract final parameter from IRC message, removing the leading colon ':' // e.g. given this string: // ":irc.tghost.co.uk 332 blabounce #test :This is a test topic!" // We want to end up with: // "This is a test topic!" void extractfinalparameter(char *string) { // Make a copy to work with char string2[strlen(string)]; // Position of colon int colonpos = -1; debugprint(DEBUG_FULL, "extractfinalparameter(): starting with '%s', strlen: %zd.\n", string, strlen(string)); // Strip the colon at position 0 if there is one stripprefix(string); // Find the colon for (size_t i = 0; i < strlen(string); i++) { if (string[i] == ':') { debugprint(DEBUG_FULL, "Found colon at position %zd!\n", i); colonpos = i; break; } } if (colonpos == -1) { debugprint(DEBUG_FULL, "no colon found, returning\n"); return; } // Build a new string starting from the next position after the colon int counter = 0; for (size_t i = colonpos + 1; i < strlen(string); i++) { string2[counter] = string[i]; counter++; } // Copy result back to original string strncpy(string, string2, counter); // Finish with null terminator string[counter] = '\0'; debugprint(DEBUG_FULL, "extractfinalparameter(): finishing with '%s', strlen: %zd.\n", string, strlen(string)); } // Extract the IRC nick from a prefix // e.g. given this string: // ":foo!bar@baz" // We want to end up with: // "foo" void extractnickfromprefix(char *string) { // Position of bang int bangpos = -1; debugprint(DEBUG_FULL, "extractnickfromprefix(): starting with '%s', strlen: %zd.\n", string, strlen(string)); // Strip the colon at position 0 if there is one stripprefix(string); // Find the bang for (size_t i = 0; i < strlen(string); i++) { if (string[i] == '!') { debugprint(DEBUG_FULL, "Found bang at position %zd!\n", i); bangpos = i; break; } } if (bangpos == -1) { debugprint(DEBUG_FULL, "no bang found, returning\n"); return; } // Terminate the string at whatever position we found the bang string[bangpos] = '\0'; debugprint(DEBUG_FULL, "extractnickfromprefix(): finishing with '%s', strlen: %zd.\n", string, strlen(string)); } // Update an existing nickuserhost string with a new nick void updatenickuserhost(char *nickuserhost, char *nick) { debugprint(DEBUG_FULL, "updatenickuserhost(): updating '%s' with '%s'.\n", nickuserhost, nick); // Position of bang int bangpos = -1; // Find the bang for (size_t i = 0; i < strlen(nickuserhost); i++) { if (nickuserhost[i] == '!') { debugprint(DEBUG_FULL, "Found bang at position %ld!\n", i); bangpos = i; break; } } if (bangpos == -1) { debugprint(DEBUG_FULL, "No bang found in existing nickuserhost, quitting!\n"); return; } // Make a new string combining the nick nick and the old nickuserhost + the offset of the bang char newstr[MAXDATASIZE]; snprintf(newstr, MAXDATASIZE, "%s%s", nick, nickuserhost + bangpos); newstr[strlen(nickuserhost) - bangpos + strlen(nick)] = '\0'; // Copy back to source string strcpy(nickuserhost, newstr); debugprint(DEBUG_FULL, "updatenickuserhost(): new nickuserhost '%s', length '%ld'.\n", nickuserhost, strlen(nickuserhost)); } // Update existing greeting strings with a new nickuserhost and new nick void updategreetings(char *greeting001, char *greeting002, char *greeting003, char *greeting004, char *greeting005a, char *greeting005b, char *greeting005c, char *newnickuserhost, char *oldnickuserhost, char *newnick, char *oldnick) { debugprint(DEBUG_FULL, "updategreetings(): updating greetings with new nickuserhost '%s' and nick '%s'.\n", newnickuserhost, newnick); // nickuserhost and greeting001's final component first // (final component as in ":servername 001 nick :Blablabla final!com@ponent" // Make copies of the nickuserhosts to work with char newnickuserhostcpy[MAXDATASIZE]; strcpy(newnickuserhostcpy, newnickuserhost); stripprefix(newnickuserhostcpy); char oldnickuserhostcpy[MAXDATASIZE]; strcpy(oldnickuserhostcpy, oldnickuserhost); stripprefix(oldnickuserhostcpy); // Find the position of the old nickuserhost in the current greeting 001 char *ret; ret = strstr(greeting001, oldnickuserhostcpy); int pos = ret - greeting001; // Terminate greeting001 where the nickuserhost begins greeting001[pos] = '\0'; // Stick the new nickuserhost in place in a temporary greeting 001 string char greetingtmp[MAXDATASIZE]; snprintf(greetingtmp, MAXDATASIZE, "%s%s", greeting001, newnickuserhostcpy); // Terminate it greetingtmp[pos + strlen(newnickuserhostcpy)] = '\0'; // Copy back to source greeting 001 strcpy(greeting001, greetingtmp); debugprint(DEBUG_FULL, "updategreetings(): new greeting 001 '%s', length '%ld'.\n", greeting001, strlen(greeting001)); // Get the new nick char newnickcpy[MAXDATASIZE]; strcpy(newnickcpy, newnick); extractnickfromprefix(newnickcpy); // greeting nicks next // (as in ":servername 00x oldnick :Blablabla" -> ":servername 00x newnick :Blablabla") updategreetingnick(greeting001, "001", newnickcpy, oldnick); updategreetingnick(greeting002, "002", newnickcpy, oldnick); updategreetingnick(greeting003, "003", newnickcpy, oldnick); updategreetingnick(greeting004, "004", newnickcpy, oldnick); if (greeting005a[0]) { updategreetingnick(greeting005a, "005", newnickcpy, oldnick); } if (greeting005b[0]) { updategreetingnick(greeting005b, "005", newnickcpy, oldnick); } if (greeting005c[0]) { updategreetingnick(greeting005c, "005", newnickcpy, oldnick); } }