summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blabouncer.c21
-rw-r--r--logging.c151
-rw-r--r--logging.h22
3 files changed, 154 insertions, 40 deletions
diff --git a/blabouncer.c b/blabouncer.c
index 0d17468..4173914 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -1,8 +1,8 @@
// TODO:
-// - Should replay log do more than PRIVMSGs?
// - Perhaps rename clients.ssl and server_ssl since they may not even be OpenSSL sockets
-// - Is it possible to replay JOINs/PARTs accurately?
+// - Is it possible to replay JOINs/PARTs?
// - Move debug output into some debug function
+// - Log TOPICs
// "server" means the real IRC server
// "client" means bouncer clients
@@ -33,6 +33,8 @@
#define SOURCE_SERVER 0
#define SOURCE_CLIENT 1
#define EXCEPT_NONE 0
+#define LOG_PRIVMSG 0
+#define LOG_JOINPART 1
// It seems to be that *message length* is max 512 bytes, but a socket read from at least UnrealIRCd seems to be up to at least 2416 (+1 for null) bytes.
// 1208 bytes with OpenSSL, 2416 bytes with plain text.
@@ -465,6 +467,7 @@ int doreplay(int sourcefd, int replayseconds, struct client *clients, struct set
// Announce the end
snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Log replay complete.", ircdstrings->ircnick);
+ sendtoclient(sourcefd, outgoingmsg, clients, settings);
return 1;
}
@@ -662,6 +665,11 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
createchannel(channels, tokens[2], "TOPIC", "TOPICWHO", "0");
}
+ // Write to normal log if logging enabled
+ if (settings->logging) {
+ logline(str, settings->ircnick, settings->basedir, LOG_JOINPART);
+ }
+
// And then send to all clients
sendtoallclients(clients, str, sourcefd, settings);
free(prefixcopy);
@@ -682,6 +690,11 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
removechannel(channels, tokens[2]);
}
+ // Write to normal log if logging enabled
+ if (settings->logging) {
+ logline(str, settings->ircnick, settings->basedir, LOG_JOINPART);
+ }
+
// And then send to all clients
sendtoallclients(clients, str, sourcefd, settings);
free(prefixcopy);
@@ -807,7 +820,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
// Write to normal log if logging enabled
if (settings->logging) {
- logprivmsg(str, settings->ircnick, settings->basedir);
+ logline(str, settings->ircnick, settings->basedir, LOG_PRIVMSG);
}
free(strcopyPtr);
@@ -1336,7 +1349,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
// Write to normal log if logging enabled
if (settings->logging) {
- logprivmsg(outgoingmsg, settings->ircnick, settings->basedir);
+ logline(outgoingmsg, settings->ircnick, settings->basedir, LOG_PRIVMSG);
}
free(strcopyPtr);
diff --git a/logging.c b/logging.c
index 569a243..a3fdda4 100644
--- a/logging.c
+++ b/logging.c
@@ -2,26 +2,46 @@
// Write the line 'str' to the relevant log file such as
// '#channel.log' or 'nickname.log'. 'ournick' is our own
-// nick and is used to determine which log file to write to.
+// nick and is used to determine which log file to write to
+// if the type is LOG_PRIVMSG.
// 'basedir' is the directory in which the 'logs' directory
// will be created in which logs are to be written.
-// Expects a string in the format:
+//
+// If LOG_PRIVMSG then it expects a string in the format:
// :from!bar@baz PRIVMSG to :hello world
-// With the ":foo!bar@baz "prefix being important.
+//
+// If LOG_JOINPART then
+// Expects a string in the format:
+// :nick!bar@baz JOIN :#blabouncer
+// or
+// :nick!bar@baz PART #blabouncer
+//
+// With the ":foo!bar@baz "prefix being important for either
+// type.
+//
// Returns 1 on success or 0 on failure.
-int logprivmsg(char *str, char *ournick, char *basedir) {
- // First, extract the "from" nick and the "to" nick or channel by splitting up the string
+int logline(char *str, char *ournick, char *basedir, int type) {
+ // Filename to write to, gets built as we go
+ char filename[MAXCHAR];
+
+ // Log line to ultimately write, gets built as we go
+ char line[MAXCHAR];
- // Track which space-separated token within this response we're on
- int counter = 0;
- // Build array of each space-separated token (TODO - Use counter to stop splitting once we reach some reasonable value - i.e. once we're definitely past commands and into just free text)
+ // Variables for LOG_JOINPART (can't define directly inside switch case)
+ int pos;
+
+ // Build array of each space-separated token
char tokens[MAXTOKENS][MAXDATASIZE];
char *token;
// Split out the first three space-separated parts of the string, leaving the rest.
+ // If LOG_PRIVMSG:
// This gets us the prefix (containing the "from" nick), the PRIVMSG command (not needed),
// and the "to" nick or channel. Plus the rest of the string intact (which is the actual
// message).
+ // If LOG_JOINPART:
+ // This gets us the prefix (containing the joined/parted nick), the JOIN/PART command (not needed),
+ // and the channel name.
for (int i = 0; i < 3; i++) {
// Try to split
if ((token = strsep(&str, " ")) == NULL) {
@@ -30,27 +50,81 @@ int logprivmsg(char *str, char *ournick, char *basedir) {
}
// Copy into the token array (strlen + 1 to get the NULL terminator)
strncpy(tokens[i], token, strlen(token) + 1);
- counter++;
+ printf("logline(): extracted '%s'.\n", tokens[i]);
}
- // Extract the username from the prefix
- extractnickfromprefix(tokens[0]);
-
- // Remove the leading ":" from the real message
- stripprefix(str);
-
- // Build the log filename
- char filename[MAXCHAR];
- // If the message was sent to us, then log it in the sender's log file
- if (strncmp(tokens[2], ournick, strlen(tokens[0])) == 0) {
- snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[0]);
- } else {
- // Otherwise log it in the "to" log file
- snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]);
+ switch(type) {
+ case LOG_PRIVMSG:
+ // Extract the username from the prefix
+ extractnickfromprefix(tokens[0]);
+
+ // Remove the leading ":" from the real message
+ stripprefix(str);
+
+ // Build the log filename
+ // If the message was sent to us, then log it in the sender's log file
+ if (strncmp(tokens[2], ournick, strlen(tokens[0])) == 0) {
+ snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[0]);
+ } else {
+ // Otherwise log it in the "to" log file
+ snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]);
+ }
+
+ printf("logline(): Logging PRIVMSG from '%s' to '%s' message '%s' in filename '%s'.\n", tokens[0], tokens[2], str, filename);
+
+ break;
+
+ case LOG_JOINPART:
+ // Find the start of the channel name
+
+ // If it's a JOIN
+ if (tokens[2][0] == ':') {
+ pos = 1;
+ } else if (tokens[2][0] == '#') {
+ // Perhaps it's a PART
+ pos = 0;
+ } else {
+ // If not found, return 0
+ return 0;
+ }
+
+ snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2] + pos);
+
+ printf("logline(): Logging JOIN/PART to/from '%s' in filename '%s'.\n", tokens[2] + pos, filename);
+
+ // Build a friendly message (e.g. ":nick!user@host JOIN #channel" -> "nick (user@host) has joined #channel")
+
+ // Find the bang in the prefix
+ char *ret;
+ int posbang;
+ if ((ret = strstr(tokens[0], "!")) != NULL) {
+ // Position within str of "!"
+ posbang = ret - tokens[0];
+ } else {
+ // No idea what happened, let's abandon ship
+ return 0;
+ }
+
+ // Make it a null character
+ tokens[0][posbang] = '\0';
+
+ // Swap JOINed or PARTed for a friendly word
+ if (strncmp(tokens[1], "JOIN", strlen("JOIN")) == 0) {
+ snprintf(tokens[1], strlen("joined") + 1, "joined");
+ } else if (strncmp(tokens[1], "PART", strlen("PART")) == 0) {
+ snprintf(tokens[1], strlen("left") + 1, "left");
+ }
+
+ // Copy the nick, then user@host, then whether it was a join or part, then the channel name the string to send
+ snprintf(line, MAXCHAR, "%s (%s) has %s %s", tokens[0] + 1, tokens[0] + posbang + 1, tokens[1], tokens[2] + pos);
+
+ break;
+
+ default :
+ printf("Unknown log type '%d', returning 0.\n", type);
+ return 0;
}
- printf("logprivmsg(): Logging from '%s' to '%s' message '%s' in filename '%s'.\n", tokens[0], tokens[2], str, filename);
-
// Make sure the log directory exists
char logdir[PATH_MAX];
snprintf(logdir, PATH_MAX, "%s/logs/", basedir);
@@ -60,12 +134,11 @@ int logprivmsg(char *str, char *ournick, char *basedir) {
printf("Error creating log directory '%s'.\n", logdir);
exit(1);
} else {
- printf("Created log directory '%s'.\n", logdir);
+ printf("logline(): log directory '%s'.\n", logdir);
}
}
FILE *fp;
- char line[MAXCHAR];
int bytes = 0;
@@ -86,13 +159,27 @@ int logprivmsg(char *str, char *ournick, char *basedir) {
snprintf(timestr, MAXCHAR, "%s", asctime(timeinfo));
timestr[strlen(timestr) - 1] = '\0';
- // Prepend the time string and "from" nick
- if (!snprintf(line, MAXCHAR, "%s <%s> %s", timestr, tokens[0], str)) {
- fprintf(stderr, "Error while log string to write!\n");
- exit(1);
+ if (type == LOG_PRIVMSG) {
+ // Prepend the time string and "from" nick
+ if (!snprintf(line, MAXCHAR, "%s <%s> %s", timestr, tokens[0], str)) {
+ fprintf(stderr, "Error while preparing log string to write!\n");
+ exit(1);
+ }
+ } else if (type == LOG_JOINPART) {
+ // Prepend the time string
+ char line2[MAXCHAR];
+ if (!snprintf(line2, MAXCHAR, "%s %s", timestr, line)) {
+ fprintf(stderr, "Error while preparing log string to write!\n");
+ exit(1);
+ }
+ // Copy back to line to write
+ snprintf(line, MAXCHAR, "%s", line2);
}
- printf("Complete log string to write: '%s', length '%ld'.\n", line, strlen(line));
+ // Ensure the line finishes with CRLF
+ appendcrlf(line);
+
+ printf("logline(): Complete log string to write: '%s', length '%ld'.\n", line, strlen(line));
// Write complete line to file
if ((bytes = fprintf(fp, line)) < 0) {
diff --git a/logging.h b/logging.h
index 726bb4d..75e6553 100644
--- a/logging.h
+++ b/logging.h
@@ -6,6 +6,7 @@
#include <time.h>
#include <limits.h>
#include <sys/stat.h>
+#include <ctype.h>
#include "functions.h"
@@ -15,16 +16,29 @@
#define SOURCE_SERVER 0
#define SOURCE_CLIENT 1
+#define LOG_PRIVMSG 0
+#define LOG_JOINPART 1
// Write the line 'str' to the relevant log file such as
// '#channel.log' or 'nickname.log'. 'ournick' is our own
-// nick and is used to determine which log file to write to.
+// nick and is used to determine which log file to write to
+// if the type is LOG_PRIVMSG.
// 'basedir' is the directory in which the 'logs' directory
// will be created in which logs are to be written.
-// Expects a string in the format:
+//
+// If LOG_PRIVMSG then it expects a string in the format:
// :from!bar@baz PRIVMSG to :hello world
-// With the ":foo!bar@baz "prefix being important.
+//
+// If LOG_JOINPART then
+// Expects a string in the format:
+// :nick!bar@baz JOIN :#blabouncer
+// or
+// :nick!bar@baz PART #blabouncer
+//
+// With the ":foo!bar@baz "prefix being important for either
+// type.
+//
// Returns 1 on success or 0 on failure.
-int logprivmsg(char *str, char *ournick, char *basedir);
+int logline(char *str, char *ournick, char *basedir, int type);
#endif