diff options
| -rw-r--r-- | TODO | 6 | ||||
| -rw-r--r-- | blabouncer.c | 400 | ||||
| -rw-r--r-- | blabouncer.conf.example | 6 | ||||
| -rw-r--r-- | config.c | 18 | ||||
| -rw-r--r-- | config.h | 4 | ||||
| -rw-r--r-- | functions.c | 77 | ||||
| -rw-r--r-- | functions.h | 13 | ||||
| -rw-r--r-- | logging.c | 15 | ||||
| -rw-r--r-- | logging.h | 3 | ||||
| -rw-r--r-- | replay.c | 10 | ||||
| -rw-r--r-- | replay.h | 4 | ||||
| -rw-r--r-- | sockets.c | 6 | ||||
| -rw-r--r-- | sockets.h | 4 | 
13 files changed, 312 insertions, 254 deletions
| @@ -9,4 +9,8 @@ Might need to #include <limits.h> in blabouncer.c to make some operating systems  Send a PING to the server before assuming a timeout is definite. -Implement daemon (background) mode. +Implement daemon (background) mode with optional foreground mode. + +Replace exit(1)s with error handling without exiting where possible. + +Remove all possible stderr/stdout/perror after startup, everything goes to printdebug() unless critical. diff --git a/blabouncer.c b/blabouncer.c index 8a718df..1ca16ea 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -34,6 +34,9 @@  #define LOG_PRIVMSG 0  #define LOG_JOINPART 1  #define LOG_TOPIC 2 +#define DEBUG_CRIT 0 +#define DEBUG_SOME 1 +#define DEBUG_FULL 2  // 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. @@ -56,8 +59,8 @@  #define DEBUGFILESKEEP 5 // How many debug files to keep around  // Global debug control -int debug = 0; -char debugpath[PATH_MAX]; +int debug = 0; // Debug verbosity ("0" for critical only, "1" for some extra info, "2" for full debug mode) +char debugpath[PATH_MAX]; // Path to debug file  struct channel {    char name[MAXCHANLENGTH]; @@ -159,7 +162,7 @@ int sendtoclient(int fd, char *strsrc, struct client *clients, struct settings *      if (clients[i].fd == fd) {        // Found client in array, check authentication status        if (!clients[i].authed && !bypass) { -        debugprint("sendtoclient(): skipping unauthenticated client with fd %d.\n", clients[i].fd); +        debugprint(DEBUG_SOME, "sendtoclient(): skipping unauthenticated client with fd %d.\n", clients[i].fd);          return 0;        }        // Break when we get to the correct fd, "i" is now the position in the clients array of our client @@ -167,9 +170,10 @@ int sendtoclient(int fd, char *strsrc, struct client *clients, struct settings *      }    } -  debugprint("sendtoclient(): sending \"%s\" (length %zd) to client with fd %d.\n", str, strlen(str), fd); +  debugprint(DEBUG_SOME, "sendtoclient(): sending \"%s\" (length %zd) to client with fd %d.\n", str, strlen(str), fd);    if (socksend(clients[i].ssl, str, strlen(str), settings->clienttls) == -1) { -    perror("error: sendtoclient() send()\n"); +    perror("error: sendtoclient() socksend()\n"); +    debugprint(DEBUG_CRIT, "error: sendtoclient() socksend() error sending to client with fd '%d', errno '%d'.\n", fd, errno);      return 0;    } @@ -203,13 +207,13 @@ int sendtoallclients(struct client *clients, char *strsrc, int except, struct se    for (int i = 0; i < MAXCLIENTS; i++) {      // Trust clientfd of 0, only we can set that ourselves      if (!except) { -      debugprint("sendtoallclients(): trusting clientfd of 0.\n"); +      debugprint(DEBUG_FULL, "sendtoallclients(): trusting clientfd of 0.\n");        break;      }      if (clients[i].fd == except) {        // Found client in array, check authentication status        if (!clients[i].authed) { -        printf("sendtoallclients(): skipping unauthenticated client with fd %d.\n", clients[i].fd); +        debugprint(DEBUG_SOME, "sendtoallclients(): skipping unauthenticated client with fd %d.\n", clients[i].fd);          return 0;        }      } @@ -225,12 +229,13 @@ int sendtoallclients(struct client *clients, char *strsrc, int except, struct se      if (clients[i].fd > 0) {        // ...and authenticated        if (!clients[i].authed) { -        debugprint("sendtoallclients(): skipping unauthenticated client with fd %d.\n", clients[i].fd); +        debugprint(DEBUG_SOME, "sendtoallclients(): skipping unauthenticated client with fd %d.\n", clients[i].fd);          continue;        } -      debugprint("sendtoallclients(): %s: sending '%s' to client with fd %d.\n", sendertype, str, clients[i].fd); +      debugprint(DEBUG_SOME, "sendtoallclients(): %s: sending '%s' to client with fd %d.\n", sendertype, str, clients[i].fd);        if (socksend(clients[i].ssl, str, strlen(str), settings->clienttls) == -1) { -        printf("error: sendtoallclients() send() with fd '%d'.\n", clients[i].fd); +        perror("error: sendtoallclients() socksend()\n"); +        debugprint(DEBUG_CRIT, "error: sendtoallclients() socksend() error sending to client with fd '%d', errno '%d'.\n", clients[i].fd, errno);        }      }    } @@ -254,21 +259,22 @@ int sendtoserver(SSL *server_ssl, char *strsrc, int str_len, int clientfd, struc    for (int i = 0; i < MAXCLIENTS; i++) {      // Trust clientfd of 0, only we can set that ourselves      if (!clientfd) { -      debugprint("sendtoserver(): trusting clientfd of 0.\n"); +      debugprint(DEBUG_FULL, "sendtoserver(): trusting clientfd of 0.\n");        break;      }      if (clients[i].fd == clientfd) {        // Found client in array, check authentication status        if (!clients[i].authed) { -        printf("sendtoserver(): skipping unauthenticated client with fd %d.\n", clients[i].fd); +        debugprint(DEBUG_SOME, "sendtoserver(): skipping unauthenticated client with fd %d.\n", clients[i].fd);          return 0;        }      }    } -  debugprint("sendtoserver(): sending %s to IRC server (length %d).\n", str, str_len); +  debugprint(DEBUG_SOME, "sendtoserver(): sending '%s' to IRC server (length %d).\n", str, str_len);    if (socksend(server_ssl, str, str_len, settings->servertls) == -1) { -    printf("error: sendtoserver() send()\n"); +    printf("error: sendtoserver() socksend()\n"); +    debugprint(DEBUG_CRIT, "error: sendtoserver() socksend() error sending to server, errno '%d'.\n", clientfd, errno);      return 0;    } @@ -280,7 +286,7 @@ int sendtoserver(SSL *server_ssl, char *strsrc, int str_len, int clientfd, struc  // Also set its authentication and registration statuses to 0.  // Also set the pending statuses to 0  int disconnectclient(int fd, struct client *clients, struct ircdstrings *ircdstrings, struct settings *settings) { -  debugprint("disconnectclient(): disconnecting client fd '%d'\n", fd); +  debugprint(DEBUG_SOME, "disconnectclient(): disconnecting client fd '%d'\n", fd);    // Alert other clients about the disconnection (don't send yet, we haven't removed from the clients array yet)    char alertmsg[MAXDATASIZE]; @@ -291,7 +297,7 @@ int disconnectclient(int fd, struct client *clients, struct ircdstrings *ircdstr    // Remove the client from the clients array    for (int i = 0; i < MAXCLIENTS; i++) {      if (clients[i].fd == fd) { -      debugprint("found and clearing fd %d from clients[%d]\n", fd, i); +      debugprint(DEBUG_FULL, "found and clearing fd %d from clients[%d]\n", fd, i);        clients[i].fd = 0;        clients[i].authed = 0;        clients[i].registered = 0; @@ -321,7 +327,7 @@ int disconnectclient(int fd, struct client *clients, struct ircdstrings *ircdstr  }  int createchannel(struct channel *channels, char *name, char *topic, char *topicwho, char *topicwhen) { -  debugprint("createchannel(): given \"%s\", \"%s\", \"%s\", and \"%s\".\n", name, topic, topicwho, topicwhen); +  debugprint(DEBUG_FULL, "createchannel(): given '%s', '%s', '%s', and '%s'.\n", name, topic, topicwho, topicwhen);    // Make sure the channel doesn't already exist    for (int i = 0; i < MAXCHANNELS; i++) { @@ -338,12 +344,12 @@ int createchannel(struct channel *channels, char *name, char *topic, char *topic        // ...and set the name and topic        strncpy(channels[i].name, name, strlen(name));        channels[i].name[strlen(name)] = '\0'; -      debugprint("createchannel(): name given was '%s', length '%ld'.\n", name, strlen(name)); -      debugprint("createchannel(): name set to '%s', length '%ld'.\n", channels[i].name, strlen(channels[i].name)); +      debugprint(DEBUG_FULL, "createchannel(): name given was '%s', length '%ld'.\n", name, strlen(name)); +      debugprint(DEBUG_FULL, "createchannel(): name set to '%s', length '%ld'.\n", channels[i].name, strlen(channels[i].name));        strncpy(channels[i].topic, topic, strlen(topic));        channels[i].topic[strlen(topic)] = '\0'; -      debugprint("createchannel(): topic given was '%s', length '%ld'.\n", topic, strlen(topic)); -      debugprint("createchannel(): topic set to '%s', length '%ld'.\n", channels[i].topic, strlen(channels[i].topic)); +      debugprint(DEBUG_FULL, "createchannel(): topic given was '%s', length '%ld'.\n", topic, strlen(topic)); +      debugprint(DEBUG_FULL, "createchannel(): topic set to '%s', length '%ld'.\n", channels[i].topic, strlen(channels[i].topic));        strncpy(channels[i].topicwho, topicwho, strlen(topicwho));        channels[i].topicwho[strlen(topicwho)] = '\0';        strncpy(channels[i].topicwhen, topicwhen, strlen(topicwhen)); @@ -354,17 +360,17 @@ int createchannel(struct channel *channels, char *name, char *topic, char *topic      }    } -  perror("error: createchannel() didn't create a channel\n"); +  debugprint(DEBUG_CRIT, "error: createchannel() didn't create a channel\n");    // TODO - Make a failed return do something to callers    return 0;  }  int setchanneltopicwhotime(struct channel *channels, char *channelname, char *who, char *when) { -  debugprint("setchanneltopicwhotime(): given \"%s\", \"%s\", and \"%s\".\n", channelname, who, when); +  debugprint(DEBUG_FULL, "setchanneltopicwhotime(): given '%s', '%s', and '%s'.\n", channelname, who, when); -  debugprint("setchanneltopicwhotime(): who: '%s' with length '%ld'.\n", who, strlen(who)); -  debugprint("setchanneltopicwhotime(): when: '%s' with length '%ld'.\n", when, strlen(when)); +  debugprint(DEBUG_FULL, "setchanneltopicwhotime(): who: '%s' with length '%ld'.\n", who, strlen(who)); +  debugprint(DEBUG_FULL, "setchanneltopicwhotime(): when: '%s' with length '%ld'.\n", when, strlen(when));    for (int i = 0; i < MAXCHANNELS; i++) {      if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) { @@ -381,7 +387,7 @@ int setchanneltopicwhotime(struct channel *channels, char *channelname, char *wh  }  int setchanneltopic(struct channel *channels, char *channelname, char *topic) { -  debugprint("setchanneltopic(): given \"%s\" and \"%s\".\n", channelname, topic); +  debugprint(DEBUG_FULL, "setchanneltopic(): given '%s' and '%s'.\n", channelname, topic);    for (int i = 0; i < MAXCHANNELS; i++) {      if (strncmp(channels[i].name, channelname, strlen(channelname)) == 0) { @@ -404,13 +410,13 @@ int getchannelcount(struct channel *channels) {      }    } -  debugprint("getchannelcount(): counted %d channels.\n", count); +  debugprint(DEBUG_FULL, "getchannelcount(): counted %d channels.\n", count);    return count;  }  int removechannel(struct channel *channels, char *name) { -  debugprint("removechannel(): given \"%s\".\n", name); +  debugprint(DEBUG_FULL, "removechannel(): given '%s'.\n", name);    // Clear its topic setter and timestamp...    setchanneltopicwhotime(channels, name, "", "0"); @@ -420,12 +426,12 @@ int removechannel(struct channel *channels, char *name) {      if (strncmp(channels[i].name, name, strlen(name)) == 0) {        // ..and NULL its name (0th character = '\0')        channels[i].name[0] = '\0'; -      debugprint("removechannel(): channel '%s' removed and topicwhen set to '%s'.\n", name, channels[i].topicwhen); +      debugprint(DEBUG_FULL, "removechannel(): channel '%s' removed and topicwhen set to '%s'.\n", name, channels[i].topicwhen);        return 1;      }    } -  perror("error: removechannel() didn't remove a channel\n"); +  debugprint(DEBUG_CRIT, "error: removechannel() didn't remove a channel\n");    // TODO - Make a failed return do something to callers    return 0; @@ -434,21 +440,21 @@ int removechannel(struct channel *channels, char *name) {  // Check if we have the NAMES for the channel 'name' already.  // Return the 1 if we do, 0 if we don't, or -1 if there's an error.  int channelgotnames(struct channel *channels, char *name) { -  debugprint("channelgotnames(): given '%s'.\n", name); +  debugprint(DEBUG_FULL, "channelgotnames(): given '%s'.\n", name);    for (int i = 0; i < MAXCHANNELS; i++) {      if (strncmp(channels[i].name, name, strlen(name)) == 0) {        if (channels[i].gotnames) { -        debugprint("channelgotnames(): channel '%s' gotnames was set, returning '%d'.\n", channels[i].name, channels[i].gotnames); +        debugprint(DEBUG_FULL, "channelgotnames(): channel '%s' gotnames was set, returning '%d'.\n", channels[i].name, channels[i].gotnames);          return 1;        } else { -        debugprint("channelgotnames(): channel '%s' gotnames was not set, returning '%d'.\n", channels[i].name, channels[i].gotnames); +        debugprint(DEBUG_FULL, "channelgotnames(): channel '%s' gotnames was not set, returning '%d'.\n", channels[i].name, channels[i].gotnames);          return 0;        }      }    }    // We didn't find the channel, this isn't good!  TODO - Do something if this happens. -  printf("channelgotnames(): channel '%s' not found, this is bad, returning -1.\n", name); +  debugprint(DEBUG_CRIT, "channelgotnames(): channel '%s' not found, this is bad, returning -1.\n", name);    return -1;  } @@ -465,13 +471,13 @@ int inchannel(struct channel *channels, char *name) {    for (int i = 0; i < MAXCHANNELS; i++) {      if (strncmp(channels[i].name, name, strlen(name)) == 0) { -      debugprint("inchannel(): in channel '%s'.\n", name); +      debugprint(DEBUG_FULL, "inchannel(): in channel '%s'.\n", name);        return 1;      }    }    // We're not in the channel -  debugprint("inchannel(): NOT in channel '%s'.\n", name); +  debugprint(DEBUG_FULL, "inchannel(): NOT in channel '%s'.\n", name);    return 0;  } @@ -479,7 +485,7 @@ int inchannel(struct channel *channels, char *name) {  // named 'channel'.  // Returns -1 if there was an error.  int channelindex(struct channel *channels, char *name) { -  debugprint("channelindex(): given '%s'.\n", name); +  debugprint(DEBUG_FULL, "channelindex(): given '%s'.\n", name);    for (int i = 0; i < MAXCHANNELS; i++) {      if (strncmp(channels[i].name, name, strlen(name)) == 0) {        return i; @@ -487,7 +493,7 @@ int channelindex(struct channel *channels, char *name) {    }    // We didn't find the channel, this isn't good!  TODO - Do something if this happens. -  printf("channelindex(): channel '%s' not found, this is bad, returning -1.\n", name); +  debugprint(DEBUG_CRIT, "channelindex(): channel '%s' not found, this is bad, returning -1.\n", name);    return -1;  } @@ -500,10 +506,10 @@ int doreplay(int sourcefd, int replayseconds, struct client *clients, struct set    // Figure out how many lines to replay    int numlines = replaylines(replayseconds, settings->basedir); -  debugprint("Replay log lines: '%d'.\n", numlines); +  debugprint(DEBUG_FULL, "Replay log lines: '%d'.\n", numlines);    if (numlines < 0) { -    debugprint("Error getting number of replay lines.\n"); +    debugprint(DEBUG_CRIT, "Error getting number of replay lines.\n");      return 0;    } else if (numlines == 0) {      snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :0 replay log lines found in the time requested, nothing to send.", ircdstrings->ircnick); @@ -518,7 +524,7 @@ int doreplay(int sourcefd, int replayseconds, struct client *clients, struct set    // Replay those lines!    for (int i = 0; i < numlines; i++) {      if (!readreplayline(replayseconds, i, outgoingmsg, settings->basedir)) { -      debugprint("Error requesting replay line.\n"); +      debugprint(DEBUG_CRIT, "Error requesting replay line.\n");        return 0;      } @@ -539,7 +545,7 @@ int doreplay(int sourcefd, int replayseconds, struct client *clients, struct set      for (int j = 0; j < 3; j++) {        // Try to split        if ((token = strsep(&strcopy, " ")) == NULL) { -        debugprint("doreplay(): error splitting string on iteration %d, exiting!\n", j); +        debugprint(DEBUG_CRIT, "doreplay(): error splitting string on iteration '%d', exiting!\n", j);          return 0;        }        // Copy into the token array (strlen + 1 to get the NULL terminator) @@ -560,7 +566,7 @@ int doreplay(int sourcefd, int replayseconds, struct client *clients, struct set        // Check if we're currently in this channel or if the log line is from us        if (!inchannel(channels, tokens[2] + offset) || strncmp(tokens[0], ircdstrings->ircnick, strlen(tokens[0])) == 0) { -        debugprint("Not sending '%s' replay line '%s'.\n", tokens[1], outgoingmsg); +        debugprint(DEBUG_FULL, "Not sending '%s' replay line '%s'.\n", tokens[1], outgoingmsg);          free(strcopyPtr);          continue;        } @@ -568,7 +574,7 @@ int doreplay(int sourcefd, int replayseconds, struct client *clients, struct set      free(strcopyPtr); -    debugprint("Sending replay line: '%s'.\n", outgoingmsg); +    debugprint(DEBUG_FULL, "Sending replay line: '%s'.\n", outgoingmsg);      sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);    } @@ -589,7 +595,7 @@ int numclients(struct client *clients) {      }    } -  debugprint("numclients(): '%d' clients connected.\n", count); +  debugprint(DEBUG_FULL, "numclients(): '%d' clients connected.\n", count);    return count;  } @@ -599,7 +605,7 @@ int numclients(struct client *clients) {  int joinautochannels(SSL *server_ssl, struct client *clients, struct settings *settings) {    if (strlen(settings->autochannels) == 0) {      // None configured -    debugprint("joinautochannels(): none configured.\n"); +    debugprint(DEBUG_FULL, "joinautochannels(): none configured.\n");      return 1;    } @@ -618,7 +624,7 @@ int joinautochannels(SSL *server_ssl, struct client *clients, struct settings *s    while ((token = strsep(&strcopy, ",")) != NULL) {      if (*token  == '\0') continue; // Skip consecutive matches      if (counter >= MAXAUTOCHANLEN) break; // Too many tokens -    debugprint("  >> Auto channel: '%s', length '%ld'.\n", token, strlen(token)); +    debugprint(DEBUG_FULL, "  >> Auto channel: '%s', length '%ld'.\n", token, strlen(token));      // Copy into the token array (strlen + 1 to get the NULL terminator)      strncpy(tokens[counter], token, strlen(token) + 1);      if (strlen(tokens[counter]) > MAXCHANLENGTH) { @@ -630,7 +636,7 @@ int joinautochannels(SSL *server_ssl, struct client *clients, struct settings *s    // Join all the channels    for (int i = 0; i < counter; i++) { -    debugprint("joinautochannels(): Joining '%s'.\n", tokens[i]); +    debugprint(DEBUG_FULL, "joinautochannels(): Joining '%s'.\n", tokens[i]);      char joinmsg[MAXDATASIZE];      snprintf(joinmsg, MAXDATASIZE, "JOIN %s", tokens[i]);      sendtoserver(server_ssl, joinmsg, strlen(joinmsg), 0, clients, settings); @@ -658,34 +664,34 @@ void tryautonick(struct ircdstrings *ircdstrings) {    // If we've already started trying autonick, just replace the last character a the new number    if (ircdstrings->autonicknum > 1) { -    debugprint("tryautonick(): already started autonick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick)); +    debugprint(DEBUG_FULL, "tryautonick(): already started autonick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick));      ircdstrings->ircnick[oldlen - 1] = ircdstrings->autonicknum + '0';      // And null terminate      ircdstrings->ircnick[oldlen] = '\0';    // If the nick is longer than or equal to the RFC 1459 max nick    // length then try sticking the number at the end    } else if (oldlen >= MAXRFCNICKLEN) { -    debugprint("tryautonick(): long old nick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick)); +    debugprint(DEBUG_FULL, "tryautonick(): long old nick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick));      // (+ '0' to make char from int)      ircdstrings->ircnick[MAXRFCNICKLEN] = ircdstrings->autonicknum + '0';      // And null terminate      ircdstrings->ircnick[MAXRFCNICKLEN + 1] = '\0';    // Otherwise, just stick it on the end (+ '0' to make char from int)    } else { -    debugprint("tryautonick(): short old nick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick)); +    debugprint(DEBUG_FULL, "tryautonick(): short old nick, starting with '%s' length '%ld'.\n", ircdstrings->ircnick, strlen(ircdstrings->ircnick));      ircdstrings->ircnick[oldlen] = ircdstrings->autonicknum + '0';      // And null terminate      ircdstrings->ircnick[oldlen + 1] = '\0';    } -  debugprint("tryautonick(): set irdstrings->ircnick to '%s'.\n", ircdstrings->ircnick); +  debugprint(DEBUG_FULL, "tryautonick(): set irdstrings->ircnick to '%s'.\n", ircdstrings->ircnick);  }  int connecttoircserver(SSL_CTX **serverctx, SSL **server_ssl, int *serversockfd, struct ircdstrings *ircdstrings, struct settings *settings, struct client *clients) {    char outgoingmsg[MAXDATASIZE]; // String to send to server    if (settings->servertls) { -    debugprint("server openssl start.\n"); +    debugprint(DEBUG_FULL, "server openssl start.\n");      *serverctx = create_openssl_context(SOURCE_SERVER);      configure_openssl_context(*serverctx, NULL, NULL);      *server_ssl = SSL_new(*serverctx); @@ -693,9 +699,9 @@ int connecttoircserver(SSL_CTX **serverctx, SSL **server_ssl, int *serversockfd,      if (SSL_connect(*server_ssl) == -1) {        ERR_print_errors_fp(stderr);      } else { -      debugprint("SSL_connect() success.\n"); +      debugprint(DEBUG_FULL, "SSL_connect() success.\n");      } -    debugprint("server openssl complete.\n"); +    debugprint(DEBUG_FULL, "server openssl complete.\n");    } else {      // If not using TLS then just slap the serversockfd into server_ssl by casting it      *server_ssl = (SSL*)(long int)*serversockfd; @@ -773,7 +779,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli    // 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)    char tokens[MAXTOKENS][MAXDATASIZE]; -  debugprint("  >> processircmessage(): Processing source %d message \"%s\"...\n", source, str); +  debugprint(DEBUG_FULL, "  >> processircmessage(): Processing source %d message \"%s\"...\n", source, str);    // Copy to a temporary string so we still have the original in case it's not processed    char *strcopy = strdup(str); @@ -785,7 +791,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli    while ((token = strsep(&strcopy, " ")) != NULL) {      if (*token  == '\0') continue; // Skip consecutive matches      if (counter >= MAXTOKENS) break; // Too many tokens -    debugprint("  >> Message Token: \"%s\", length %zd.\n", token, strlen(token)); +    debugprint(DEBUG_FULL, "  >> Message Token: \"%s\", length %zd.\n", token, strlen(token));      // Copy into the token array (strlen + 1 to get the NULL terminator)      strncpy(tokens[counter], token, strlen(token) + 1);      counter++; @@ -801,7 +807,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Server PING received?  If so, send a PONG back with the next element as the argument.        if (strncmp(tokens[0], "PING", strlen(tokens[0])) == 0) { -        debugprint("Server PING found and it is: %s with length %zd!  Sending response...\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Server PING found and it is: %s with length %zd!  Sending response...\n", tokens[0], strlen(tokens[0]));          char outgoingmsg[MAXDATASIZE]; // String to send to server          if (!snprintf(outgoingmsg, MAXDATASIZE, "PONG %s", tokens[1])) { // TODO - Make sure tokens[1] actually has a token @@ -818,16 +824,16 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Prefix received?  TODO - Care about what the prefix is - what if it's a different server/network/whatever?        if (tokens[0][0] == ':') { -        debugprint("Prefix found: '%s'!  Next token is '%s', length %zd.\n", tokens[0], tokens[1], strlen(tokens[1])); +        debugprint(DEBUG_FULL, "Prefix found: '%s'!  Next token is '%s', length %zd.\n", tokens[0], tokens[1], strlen(tokens[1]));          // Greetings 001 through to 005, store in ircdstrings array for resending when clients connect          // Also store our nick!user@host from greeting 001          // Also store the real IRCd's name from greeting 004          if (strncmp(tokens[1], "001", strlen(tokens[1])) == 0) { -          debugprint("Found greeting 001 (%s) (length %zd), storing in ircdstrings struct.\n", str, strlen(str)); +          debugprint(DEBUG_FULL, "Found greeting 001 (%s) (length %zd), storing in ircdstrings struct.\n", str, strlen(str));            strncpy(ircdstrings->greeting001, str, strlen(str));            // Null the end of the string            ircdstrings->greeting001[strlen(str)] = '\0'; -          debugprint("Storing our nick!user@host (:%s) from greeting 001 in ircdstrings struct.\n", tokens[counter - 1]); +          debugprint(DEBUG_FULL, "Storing our nick!user@host (:%s) from greeting 001 in ircdstrings struct.\n", tokens[counter - 1]);            // Prepend a colon (:) first since everything (so far) needs one            if (!snprintf(ircdstrings->nickuserhost, MAXDATASIZE, ":%s", tokens[counter - 1])) {              fprintf(stderr, "Error while preparing nickuserhost for storage!\n"); @@ -835,29 +841,29 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            }            // Null the end of the new string            ircdstrings->nickuserhost[strlen(tokens[counter - 1]) + 1] = '\0'; // +1 for the inserted colon -          debugprint("nickuserhost '%s' stored.\n", ircdstrings->nickuserhost); +          debugprint(DEBUG_FULL, "nickuserhost '%s' stored.\n", ircdstrings->nickuserhost);            free(strcopyPtr);            return 1;          } else if (strncmp(tokens[1], "002", strlen(tokens[1])) == 0) { -          debugprint("Found greeting 002 (%s), storing in ircdstrings struct.\n", str); +          debugprint(DEBUG_FULL, "Found greeting 002 (%s), storing in ircdstrings struct.\n", str);            strncpy(ircdstrings->greeting002, str, strlen(str));            // Null the end of the string            ircdstrings->greeting002[strlen(str)] = '\0';            free(strcopyPtr);            return 1;          } else if (strncmp(tokens[1], "003", strlen(tokens[1])) == 0) { -          debugprint("Found greeting 003 (%s), storing in ircdstrings struct.\n", str); +          debugprint(DEBUG_FULL, "Found greeting 003 (%s), storing in ircdstrings struct.\n", str);            strncpy(ircdstrings->greeting003, str, strlen(str));            // Null the end of the string            ircdstrings->greeting003[strlen(str)] = '\0';            free(strcopyPtr);            return 1;          } else if (strncmp(tokens[1], "004", strlen(tokens[1])) == 0) { -          debugprint("Found greeting 004 (%s), storing in ircdstrings struct.\n", str); +          debugprint(DEBUG_FULL, "Found greeting 004 (%s), storing in ircdstrings struct.\n", str);            strncpy(ircdstrings->greeting004, str, strlen(str));            // Null the end of the string            ircdstrings->greeting004[strlen(str)] = '\0'; -          debugprint("Storing the real IRCd's name (%s) from greeting 004 in ircdstrings struct.\n", tokens[3]); +          debugprint(DEBUG_FULL, "Storing the real IRCd's name (%s) from greeting 004 in ircdstrings struct.\n", tokens[3]);            strncpy(ircdstrings->ircdname, tokens[3], strlen(tokens[3]));            // Null the end of the string            ircdstrings->ircdname[strlen(tokens[3])] = '\0'; @@ -872,7 +878,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            if (ircdstrings->reconnecting) {              // First tell clients if our nick changed              if (!strcmp(ircdstrings->ircnick, ircdstrings->oldnick) == 0) { -              debugprint("Telling clients about nick change.\n"); +              debugprint(DEBUG_SOME, "Telling clients about nick change.\n");                char nickmsg[MAXDATASIZE];                snprintf(nickmsg, MAXDATASIZE, ":%s NICK :%s", ircdstrings->oldnick, ircdstrings->ircnick);                sendtoallclients(clients, nickmsg, sourcefd, settings); @@ -885,12 +891,12 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              for (int i = 0; i < channelcount; i++) {                // Skip this one and increment channelcount if it's a blank channel                if (!channels[i].name[0]) { -                  debugprint("Reconnection: Skipping channel[%d], incrementing channelcount.\n", i); +                  debugprint(DEBUG_FULL, "Reconnection: Skipping channel[%d], incrementing channelcount.\n", i);                    channelcount++;                    continue;                } -              debugprint("Reconnection: Re-joining '%s'.\n", channels[i].name); +              debugprint(DEBUG_SOME, "Reconnection: Re-joining '%s'.\n", channels[i].name);                char joinmsg[MAXDATASIZE];                snprintf(joinmsg, MAXDATASIZE, "JOIN %s", channels[i].name); @@ -921,7 +927,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            free(strcopyPtr);            return 1;          } else if (strncmp(tokens[1], "005", strlen(tokens[1])) == 0) { -          debugprint("Found greeting 005 (%s), storing in ircdstrings struct.\n", str); +          debugprint(DEBUG_FULL, "Found greeting 005 (%s), storing in ircdstrings struct.\n", str);            // Find an empty greeting005 string in ircdstrings and store in there...            if (!ircdstrings->greeting005a[0]) {              strncpy(ircdstrings->greeting005a, str, strlen(str)); @@ -934,7 +940,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              ircdstrings->greeting005c[strlen(str)] = '\0';            } else {              // ...or if they are all fill, discard - TODO - Support more than three greeting005 strings! -            debugprint("Already stored three greeting 005 strings, discarding this one.\n"); +            debugprint(DEBUG_CRIT, "Already stored three greeting 005 strings, discarding this one.\n");            }            free(strcopyPtr);            return 1; @@ -942,11 +948,11 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server JOIN received?  Add to our local channel array if it's us, or record the user in the channel if it's not us.          if (strncmp(tokens[1], "JOIN", strlen(tokens[1])) == 0) { -          debugprint("Server JOIN found and it is: %s with length %zd!  Next token is '%s'.  Adding to local channel list if it's us.\n", tokens[0], strlen(tokens[0]), tokens[2]); +          debugprint(DEBUG_FULL, "Server JOIN found and it is: %s with length %zd!  Next token is '%s'.  Adding to local channel list if it's us.\n", tokens[0], strlen(tokens[0]), tokens[2]);            // Next token should be the channel name but it probably needs the leading ':' stripping -          debugprint("processircmessage(): Channel name was '%s'\n", tokens[2]); +          debugprint(DEBUG_FULL, "processircmessage(): Channel name was '%s'\n", tokens[2]);            stripprefix(tokens[2]); -          debugprint("processircmessage(): Channel name now '%s'\n", tokens[2]); +          debugprint(DEBUG_FULL, "processircmessage(): Channel name now '%s'\n", tokens[2]);            // If the user JOINing is us, then we must have joined a channel, so add to our local channel array.            // Copy to a temporary string so we still have the original in case we need it @@ -954,12 +960,12 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            // Just get the nick for comparison            extractnickfromprefix(prefixcopy);            if (strncmp(prefixcopy, ircdstrings->ircnick, strlen(tokens[0])) == 0) { -            debugprint("Server JOIN: nick is ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->ircnick); +            debugprint(DEBUG_FULL, "Server JOIN: nick is ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->ircnick);              // TODO - Saner way to initialise this since we don't have the variables yet?              // TODO - Defaulting to type '=' which is "public" since I don't know what else to guess.              createchannel(channels, tokens[2], "TOPIC", "TOPICWHO", "0");            } else { -            debugprint("Server JOIN: nick is NOT ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->ircnick); +            debugprint(DEBUG_FULL, "Server JOIN: nick is NOT ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->ircnick);            }            // And then send to all clients @@ -982,7 +988,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server PART received?  Remove from our local channel list if it's us.          if (strncmp(tokens[1], "PART", strlen(tokens[1])) == 0) { -          debugprint("Server PART found and it is: %s with length %zd!  Next token is '%s'.  Removing from local channel list if it's us.\n", tokens[0], strlen(tokens[0]), tokens[2]); +          debugprint(DEBUG_FULL, "Server PART found and it is: %s with length %zd!  Next token is '%s'.  Removing from local channel list if it's us.\n", tokens[0], strlen(tokens[0]), tokens[2]);            // If the user PARTing is us, then we must have left a channel, so remove it from our local channel array.            // (If it's not us, then it's another user PARTing a channel, so just pass straight through to letting all our clients know.) @@ -991,10 +997,10 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            // Just get the nick for comparison            extractnickfromprefix(prefixcopy);            if (strncmp(prefixcopy, ircdstrings->ircnick, strlen(tokens[0])) == 0) { -            debugprint("Server PART: nick is ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->ircnick); +            debugprint(DEBUG_FULL, "Server PART: nick is ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->ircnick);              removechannel(channels, tokens[2]);            } else { -            debugprint("Server PART: nick is NOT ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->ircnick); +            debugprint(DEBUG_FULL, "Server PART: nick is NOT ours ('%s' vs '%s').\n", prefixcopy, ircdstrings->ircnick);            }            // And then send to all clients @@ -1024,7 +1030,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            setchanneltopicwhotime(channels, tokens[3], "", "0");          // Server 332 (RPL_TOPIC) set the channel topic          } else if (strncmp(tokens[1], "332", strlen(tokens[1])) == 0) { -          debugprint("Server 332 (RPL_TOPIC) found, extracting topic and storing in channel struct.\n"); +          debugprint(DEBUG_FULL, "Server 332 (RPL_TOPIC) found, extracting topic and storing in channel struct.\n");            // Need to extract the final parameter as topics can have spaces            // Copy to a temporary string so we still have the original in case we need it            char *topiccopy = strdup(str); @@ -1033,24 +1039,24 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            free(topiccopy);          // Server 333 (RPL_TOPICWHOTIME) set the channel topic setter and the time it was set          } else if (strncmp(tokens[1], "333", strlen(tokens[1])) == 0) { -          debugprint("Server 333 (RPL_TOPICWHOTIME) found, extracting who and when, and storing in channel struct.\n"); +          debugprint(DEBUG_FULL, "Server 333 (RPL_TOPICWHOTIME) found, extracting who and when, and storing in channel struct.\n");            setchanneltopicwhotime(channels, tokens[3], tokens[4], tokens[5]);          // Server 353 (RPL_NAMREPLY), relay to all clients if we've just JOINed the channel, or relay to any clients          // who were pending RPL_NAMREPLYs if it's an existing channel.          } else if (strncmp(tokens[1], "353", strlen(tokens[1])) == 0) {            // It must be a new channel and we don't have the NAMES            if (!channelgotnames(channels, tokens[4])) { -            debugprint("Server 353 received for a new channel, sending to all clients.\n"); +            debugprint(DEBUG_FULL, "Server 353 received for a new channel, sending to all clients.\n");              // Relay to all clients              sendtoallclients(clients, str, sourcefd, settings);            } else {              // We were already in the channel and have the NAMES -            debugprint("Server 353 received for an existing channel, sending to all clients who were pending RPL_NAMREPLYs.\n"); +            debugprint(DEBUG_FULL, "Server 353 received for an existing channel, sending to all clients who were pending RPL_NAMREPLYs.\n");              // If any clients were pending RPL_NAMREPLYs, send this on to them              // TODO - Make sure clients only get the ones they were waiting on in case there are multiple conflicting requests going on at once              for (int i = 0; i < MAXCLIENTS; i++) {                if (clients[i].pendingnames > 0) { -                debugprint("Sending 353 RPL_NAMREPLY for channel '%s' to client with fd '%d' who was pending %d RPL_NAMREPLYs.\n", tokens[4], clients[i].fd, clients[i].pendingnames); +                debugprint(DEBUG_FULL, "Sending 353 RPL_NAMREPLY for channel '%s' to client with fd '%d' who was pending %d RPL_NAMREPLYs.\n", tokens[4], clients[i].fd, clients[i].pendingnames);                  sendtoclient(clients[i].fd, str, clients, settings, 0);                }              } @@ -1063,7 +1069,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            int channelelement;            // It must be a new channel and we don't have the NAMES            if (!(channelelement = channelgotnames(channels, tokens[3]))) { -            debugprint("Server 366 received for a new channel, sending to all clients and set as got names.\n"); +            debugprint(DEBUG_FULL, "Server 366 received for a new channel, sending to all clients and set as got names.\n");              // We have the names now!              channels[channelindex(channels, tokens[3])].gotnames = 1;              // Relay to all clients @@ -1071,14 +1077,15 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            } else {              // We were already in the channel and have the NAMES              // TODO - Make sure clients only get the ones they were waiting on in case there are multiple conflicting requests going on at once -            debugprint("Server 366 received for an existing channel, sending to all clients who were pending RPL_NAMREPLYs and decrementing their pendingnames count.\n"); +            debugprint(DEBUG_FULL, "Server 366 received for an existing channel, sending to all clients who were pending RPL_NAMREPLYs and decrementing their pendingnames count.\n");              for (int i = 0; i < MAXCLIENTS; i++) {                if (clients[i].pendingnames > 0) {                  sendtoclient(clients[i].fd, str, clients, settings, 0);                  // And decrement their pendingnames count -                debugprint("Decrementing pendingnames due 366 RPL_ENDOFNAMES to for channel '%s' to client with fd '%d' who was pending %d RPL_NAMREPLYs.\n", tokens[3], clients[i].fd, clients[i].pendingnames); +                debugprint(DEBUG_FULL, "Decrementing pendingnames due 366 RPL_ENDOFNAMES to for channel '%s' to client with fd '%d' who was pending %d RPL_NAMREPLYs.\n", +                           tokens[3], clients[i].fd, clients[i].pendingnames);                  clients[i].pendingnames--; -                debugprint("Client with fd '%d' has '%d' pendingnames left.\n", clients[i].fd, clients[i].pendingnames); +                debugprint(DEBUG_FULL, "Client with fd '%d' has '%d' pendingnames left.\n", clients[i].fd, clients[i].pendingnames);                }              }            } @@ -1088,7 +1095,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server TOPIC received?  Update our local channel topic info then relay to clients.          if (strncmp(tokens[1], "TOPIC", strlen(tokens[1])) == 0) { -          debugprint("Server TOPIC found and it is: %s with length %zd!  Next token is '%s'.  Updating our local channel topic info.\n", tokens[0], strlen(tokens[0]), tokens[2]); +          debugprint(DEBUG_FULL, "Server TOPIC found and it is: %s with length %zd!  Next token is '%s'.  Updating our local channel topic info.\n", +                     tokens[0], strlen(tokens[0]), tokens[2]);            // Set the topic itself @@ -1135,7 +1143,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server PRIVMSG received?  Relay to all clients and write to replay log.          if (strncmp(tokens[1], "PRIVMSG", strlen(tokens[1])) == 0) { -          debugprint("Server PRIVMSG found and it is: %s with length %zd!  Next token is '%s'.  Relaying to all clients.\n", tokens[0], strlen(tokens[0]), tokens[2]); +          debugprint(DEBUG_FULL, "Server PRIVMSG found and it is: %s with length %zd!  Next token is '%s'.  Relaying to all clients.\n", +                     tokens[0], strlen(tokens[0]), tokens[2]);            sendtoallclients(clients, str, sourcefd, settings); @@ -1157,7 +1166,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // 1. Find out if it was us and change ircnick and nickuserhost if so          // 2. Either way, relay to all clients          if (strncmp(tokens[1], "NICK", strlen(tokens[1])) == 0) { -          debugprint("Server NICK found and it is: %s with length %zd!  Next token is '%s'.  Updating records and relaying to all clients.\n", tokens[0], strlen(tokens[0]), tokens[2]); +          debugprint(DEBUG_FULL, "Server NICK found and it is: %s with length %zd!  Next token is '%s'.  Updating records and relaying to all clients.\n", +                     tokens[0], strlen(tokens[0]), tokens[2]);            // Was it us?            // Copy to a temporary string so we still have the original in case we need it @@ -1165,22 +1175,24 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            // Just get the nick for comparison            extractnickfromprefix(svrprefixcopy);            if (strncmp(ircdstrings->ircnick, svrprefixcopy, strlen(ircdstrings->ircnick)) == 0) { -            debugprint("Server NICK: nick is ours ('%s' vs '%s').\n", svrprefixcopy, ircdstrings->ircnick); +            debugprint(DEBUG_FULL, "Server NICK: nick is ours ('%s' vs '%s').\n", svrprefixcopy, ircdstrings->ircnick);              // Make a copy of the old nickuserhost for updategreetings() below              char *nickuserhostcpy = strdup(ircdstrings->nickuserhost);              // Update nickuserhost with the new :nick!user@host              updatenickuserhost(ircdstrings->nickuserhost, tokens[2]); -            debugprint("Updated nickuserhost to '%s'.\n", ircdstrings->nickuserhost); +            debugprint(DEBUG_FULL, "Updated nickuserhost to '%s'.\n", ircdstrings->nickuserhost);              // Prepare to update ircnick and greetings strings              // Temporary copy of new nickuserhost              char *prefixcopy = strdup(ircdstrings->nickuserhost);              // Get nick from it              extractnickfromprefix(prefixcopy);              // Update greeting strings for relaying to new clients -            updategreetings(ircdstrings->greeting001, ircdstrings->greeting002, ircdstrings->greeting003, ircdstrings->greeting004, ircdstrings->greeting005a, ircdstrings->greeting005b, ircdstrings->greeting005c, ircdstrings->nickuserhost, nickuserhostcpy, tokens[2], ircdstrings->ircnick); +            updategreetings(ircdstrings->greeting001, ircdstrings->greeting002, ircdstrings->greeting003, ircdstrings->greeting004, +                            ircdstrings->greeting005a, ircdstrings->greeting005b, ircdstrings->greeting005c, ircdstrings->nickuserhost, +                            nickuserhostcpy, tokens[2], ircdstrings->ircnick);              // Update our nick              strcpy(ircdstrings->ircnick, prefixcopy); -            debugprint("Updated ircnick to '%s'.\n", ircdstrings->ircnick); +            debugprint(DEBUG_FULL, "Updated ircnick to '%s'.\n", ircdstrings->ircnick);              free(nickuserhostcpy);              free(prefixcopy);            } @@ -1195,7 +1207,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server MODE received?  See what sort it is and act accordingly.          if (strncmp(tokens[1], "MODE", strlen(tokens[1])) == 0) { -          debugprint("Server MODE found and it is: %s with length %zd!  Next token is '%s'.  Analysing...\n", tokens[1], strlen(tokens[1]), tokens[2]); +          debugprint(DEBUG_FULL, "Server MODE found and it is: %s with length %zd!  Next token is '%s'.  Analysing...\n", +                     tokens[1], strlen(tokens[1]), tokens[2]);            // 4 tokens could be either our initial mode or a channel mode (or something else - TODO - what else?)            if (counter == 4) { @@ -1204,7 +1217,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              snprintf(comparison, MAXDATASIZE, ":%s MODE %s :", ircdstrings->ircnick, ircdstrings->ircnick);              if (strncmp(str, comparison, strlen(comparison)) == 0) {                // Looks like it! -              debugprint("Our initial MODE found (%s), storing for later.\n", tokens[3]); +              debugprint(DEBUG_FULL, "Our initial MODE found (%s), storing for later.\n", tokens[3]);                // Store in ircdstrings for when clients connect and relay to current clients.                strcpy(ircdstrings->mode, tokens[3]); @@ -1218,7 +1231,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              // Might be a channel mode (e.g. ":nick!user@host MODE #channel +s")              if (tokens[2][0] == '#') {                // Looks like it!  Tell all clients. -              debugprint("Channel MODE found (%s %s), telling all clients.\n", tokens[2], tokens[3]); +              debugprint(DEBUG_FULL, "Channel MODE found (%s %s), telling all clients.\n", tokens[2], tokens[3]);                sendtoallclients(clients, str, sourcefd, settings);                free(strcopyPtr); @@ -1235,7 +1248,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server 324 (RPL_CHANNELMODEIS) received?  Send to any clients who requested a channel MODE.          if (strncmp(tokens[1], "324", strlen(tokens[1])) == 0) { -          debugprint("Server 324 (RPL_CHANNELMODEIS) found and it is: %s with length %zd!  Sending to clients who are pending this.\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Server 324 (RPL_CHANNELMODEIS) found and it is: %s with length %zd!  Sending to clients who are pending this.\n", +                     tokens[1], strlen(tokens[1]));            // Relay to all pending clients            for (int i = 0; i < MAXCLIENTS; i++) { @@ -1252,7 +1266,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server 368 (RPL_ENDOFBANLIST) received?  Send to any clients who requested a ban MODE query. - TODO - Identify and handle start/middle of ban responses.          if (strncmp(tokens[1], "368", strlen(tokens[1])) == 0) { -          debugprint("Server 368 (RPL_ENDOFBANLIST) found and it is: %s with length %zd!  Sending to clients who are pending this.\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Server 368 (RPL_ENDOFBANLIST) found and it is: %s with length %zd!  Sending to clients who are pending this.\n", +                     tokens[1], strlen(tokens[1]));            // Relay to all pending clients            for (int i = 0; i < MAXCLIENTS; i++) { @@ -1269,7 +1284,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server 329 (RPL_CREATIONTIME), 352 (RPL_WHOREPLY), or 315 (RPL_ENDOFWHO) received?  Send to any clients who requested a WHO.          if (strncmp(tokens[1], "329", strlen(tokens[1])) == 0 || strncmp(tokens[1], "352", strlen(tokens[1])) == 0 || strncmp(tokens[1], "315", strlen(tokens[1])) == 0) { -          debugprint("Server 329 (RPL_CREATIONTIME), 352 (RPL_WHOREPLY), or 315 (RPL_ENDOFWHO) found and it is: %s with length %zd!  Sending to clients who are pending one of these.\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Server 329 (RPL_CREATIONTIME), 352 (RPL_WHOREPLY), or 315 (RPL_ENDOFWHO) found and it is: %s with length %zd!  Sending to clients who are pending one of these.\n", +                     tokens[1], strlen(tokens[1]));            // Relay to all pending clients            for (int i = 0; i < MAXCLIENTS; i++) { @@ -1288,7 +1304,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server 321 (RPL_LISTSTART), 322 (RPL_LIST), or 323 (RPL_LISTEND) received?  Send to any clients who requested a WHO.          if (strncmp(tokens[1], "321", strlen(tokens[1])) == 0 || strncmp(tokens[1], "322", strlen(tokens[1])) == 0 || strncmp(tokens[1], "323", strlen(tokens[1])) == 0) { -          debugprint("Server 321 (RPL_LISTSTART), 322 (RPL_LIST), or 323 (RPL_LISTEND) found and it is: %s with length %zd!  Sending to clients who are pending one of these.\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Server 321 (RPL_LISTSTART), 322 (RPL_LIST), or 323 (RPL_LISTEND) found and it is: %s with length %zd!  Sending to clients who are pending one of these.\n", +                     tokens[1], strlen(tokens[1]));            // Relay to all pending clients            for (int i = 0; i < MAXCLIENTS; i++) { @@ -1313,7 +1330,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              strncmp(tokens[1], "317", strlen(tokens[1])) == 0 || strncmp(tokens[1], "319", strlen(tokens[1])) == 0 ||              strncmp(tokens[1], "320", strlen(tokens[1])) == 0 || strncmp(tokens[1], "671", strlen(tokens[1])) == 0 ||              strncmp(tokens[1], "318", strlen(tokens[1])) == 0) { -          debugprint("Server 307 RPL_SUSERHOST, 311 RPL_WHOISUSER, 312 RPL_WHOISSERVER, 313 (RPL_WHOISOPERATOR), 317 RPL_WHOISIDLE, " +          debugprint(DEBUG_FULL, "Server 307 RPL_SUSERHOST, 311 RPL_WHOISUSER, 312 RPL_WHOISSERVER, 313 (RPL_WHOISOPERATOR), 317 RPL_WHOISIDLE, "                   "319 RPL_WHOISCHANNELS, 320 (RPL_WHOISSPECIAL), 671 (RPL_WHOISSECURE), or 318 RPL_ENDOFWHOIS found and it is: "                   "%s with length %zd!  Sending to clients who are pending one of these.\n", tokens[1], strlen(tokens[1])); @@ -1335,8 +1352,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server 314 (RPL_WHOWASUSER), 406 (ERR_WASNOSUCHNICK), or 369 (RPL_ENDOFWHOWAS) received?          // Send to any clients who requested a WHOWAS.          if (strncmp(tokens[1], "314", strlen(tokens[1])) == 0 || strncmp(tokens[1], "406", strlen(tokens[1])) == 0 || strncmp(tokens[1], "369", strlen(tokens[1])) == 0) { -          debugprint("314 (RPL_WHOWASUSER), 406 (ERR_WASNOSUCHNICK), or 369 (RPL_ENDOFWHOWAS) " -                 "found and it is: %s with length %zd!  Sending to clients who are pending one of these.\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "314 (RPL_WHOWASUSER), 406 (ERR_WASNOSUCHNICK), or 369 (RPL_ENDOFWHOWAS) " +                     "found and it is: %s with length %zd!  Sending to clients who are pending one of these.\n", tokens[1], strlen(tokens[1]));            // Relay to all pending clients            for (int i = 0; i < MAXCLIENTS; i++) { @@ -1355,7 +1372,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server 312 (RPL_WHOISSERVER) received?  Check to see if anyone was pending a WHOIS or a WHOWAS and send to them, if not send to everyone.          if (strncmp(tokens[1], "312", strlen(tokens[1])) == 0) { -          debugprint("Server 312 (RPL_WHOISSERVER) found and it is: %s with length %zd!  Sending to clients who are pending this or to everyone if nobody is.\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Server 312 (RPL_WHOISSERVER) found and it is: %s with length %zd!  Sending to clients who are pending this or to everyone if nobody is.\n", +                     tokens[1], strlen(tokens[1]));            int waspending = 0; @@ -1381,7 +1399,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server 401 (ERR_NOSUCHNICK) received?  Check to see if anyone was pending a WHOIS and send to them,          // if not send to everyone (401 was probably in reply to something else like a PRIVMSG).          if (strncmp(tokens[1], "401", strlen(tokens[1])) == 0) { -          debugprint("Server 401 (ERR_NOSUCHNICK) found and it is: %s with length %zd!  Sending to clients who are pending this or to everyone if nobody is.\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Server 401 (ERR_NOSUCHNICK) found and it is: %s with length %zd!  Sending to clients who are pending this or to everyone if nobody is.\n", +                     tokens[1], strlen(tokens[1]));            int waspending = 0; @@ -1406,7 +1425,8 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server 432 (ERR_ERRONEUSNICKNAME) or 433 (ERR_NICKNAMEINUSE) received?  See which nick we're on and try another.          // (But only if we're not already registered with the real IRC server.)          if ((strncmp(tokens[1], "432", strlen(tokens[1])) == 0 || strncmp(tokens[1], "433", strlen(tokens[1])) == 0) && !strlen(ircdstrings->greeting004)) { -          debugprint("Server 432 (ERR_ERRONEUSNICKNAME) or 433 (ERR_NICKNAMEINUSE) found and it is: %s with length %zd!  Trying another nick...\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_SOME, "Server 432 (ERR_ERRONEUSNICKNAME) or 433 (ERR_NICKNAMEINUSE) found and it is: %s with length %zd!  Trying another nick...\n", +                     tokens[1], strlen(tokens[1]));            // Try to get nick2 and nick3 from the configuration file            char nick2[MAXNICKLENGTH]; @@ -1427,12 +1447,12 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              // Has nick2 already been tried?              } else if (strncmp(ircdstrings->ircnick, nick2, strlen(settings->ircnick)) == 0) {                // Then try nick3 -              debugprint("Trying nick3, nick2 was already tried.\n"); +              debugprint(DEBUG_SOME, "Trying nick3, nick2 was already tried.\n");                strcpy(ircdstrings->ircnick, nick3);              // Have neither been tried?              } else {                // Then try nick2 -              debugprint("Trying nick2, nick3 is also configured.\n"); +              debugprint(DEBUG_SOME, "Trying nick2, nick3 is also configured.\n");                strcpy(ircdstrings->ircnick, nick2);              }            // Do we only have a nick2?  (And not tried autonick yet.) @@ -1443,7 +1463,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli                tryautonick(ircdstrings);              } else {                // Then try it -              debugprint("Trying nick2, nick3 is not configured.\n"); +              debugprint(DEBUG_SOME, "Trying nick2, nick3 is not configured.\n");                strcpy(ircdstrings->ircnick, nick2);              }            // Do we have neither?  (Or have already started autonick.) @@ -1467,7 +1487,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Server CAP received?          if (strncmp(tokens[1], "CAP", strlen(tokens[1])) == 0) { -          debugprint("Server CAP found and it is: %s with length %zd!  Analysing...\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Server CAP found and it is: %s with length %zd!  Analysing...\n", tokens[1], strlen(tokens[1]));            // If the server said "CAP <ournick> ACK :multi-prefix" then it must have approved our CAP multi-prefix request            if (counter == 5) {              if (strncmp(tokens[2], ircdstrings->ircnick, strlen(tokens[2])) == 0 && @@ -1477,15 +1497,15 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              }            }            // We didn't handle it -          debugprint("Unhandled server CAP response.\n"); +          debugprint(DEBUG_FULL, "Unhandled server CAP response.\n");          }          // Server NOTICE received?  Handle and log if it's from a user, otherwise let pass through to default handler.          if (strncmp(tokens[1], "NOTICE", strlen(tokens[1])) == 0) { -          debugprint("Server NOTICE found and it is: %s with length %zd!  Analysing...\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Server NOTICE found and it is: %s with length %zd!  Analysing...\n", tokens[1], strlen(tokens[1]));            // If the first token is a nick!user@host then it's probably from a user            if (strstr(tokens[0], "!") != NULL && strstr(tokens[0], "@") != NULL) { -            debugprint("Server NOTICE appears to be from a user, sending to all clients and logging.\n"); +            debugprint(DEBUG_FULL, "Server NOTICE appears to be from a user, sending to all clients and logging.\n");              sendtoallclients(clients, str, 0, settings); @@ -1502,7 +1522,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              free(strcopyPtr);              return 1;            } else { -            debugprint("Server NOTICE does not appear to be from a user, passing through.\n"); +            debugprint(DEBUG_FULL, "Server NOTICE does not appear to be from a user, passing through.\n");            }          }        } @@ -1514,13 +1534,13 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // PASS received?  User is trying to log in, check their password.        if (strncasecmp(tokens[0], "PASS", strlen(tokens[0])) == 0) {          if (checkpassword(tokens[1], settings->conffile)) { -          debugprint("Password accepted!  Setting fd %d to authenticated.\n", sourcefd); +          debugprint(DEBUG_FULL, "Password accepted!  Setting fd %d to authenticated.\n", sourcefd);            // Find the client in the clients array and set them as authenticated            for (int i = 0; i < MAXCLIENTS; i++) {              if (clients[i].fd == sourcefd) {                // Found client in array, set to authenticated                clients[i].authed = 1; -              debugprint("Found and authenticated fd in arr_authed.\n"); +              debugprint(DEBUG_FULL, "Found and authenticated fd in arr_authed.\n");                // Alert other clients about the successful authentication                char alertmsg[MAXDATASIZE];                if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client with fd %d has successfully authenticated.", ircdstrings->ircnick, sourcefd)) { @@ -1532,7 +1552,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              }            }          } else { -          debugprint("Password rejected, disconnecting fd %d.\n", sourcefd); +          debugprint(DEBUG_SOME, "Password rejected, disconnecting fd %d.\n", sourcefd);            disconnectclient(sourcefd, clients, ircdstrings, settings);            // Alert other clients about the failed authentication            char alertmsg[MAXDATASIZE]; @@ -1552,9 +1572,9 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        if (strncasecmp(tokens[0], "CAP", strlen(tokens[0])) == 0) {          // But only do something if the real server told us it had a CAP (only multi-prefix for now)          if (ircdstrings->capmultiprefix == 1) { -          debugprint("Client CAP received and the server supports CAPs, continuing.\n"); +          debugprint(DEBUG_FULL, "Client CAP received and the server supports CAPs, continuing.\n");          } else { -          debugprint("Client CAP received but the server doesn't support CAPs, returning.\n"); +          debugprint(DEBUG_FULL, "Client CAP received but the server doesn't support CAPs, returning.\n");            free(strcopyPtr);            return 1;          } @@ -1594,7 +1614,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // We're past PASS in the list of possible commands, so ignore        // anything else the client says if they are not authenticated yet.        if (!clients[arrindex(clients, sourcefd)].authed) { -        debugprint("Ignoring client command '%s' from sourcefd '%d' as not authenticated yet.\n", tokens[0], sourcefd); +        debugprint(DEBUG_CRIT, "Ignoring client command '%s' from sourcefd '%d' as not authenticated yet.\n", tokens[0], sourcefd);          free(strcopyPtr);          return 1;        } @@ -1655,15 +1675,15 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // Storing separately so we can skip over blank channels.          int channelcount = getchannelcount(channels);          // Set the client as pending RPL_NAMREPLYs for 'channelcount' channels -        debugprint("Setting pendingnames to '%d' for client with fd '%d'.\n", channelcount, sourcefd); +        debugprint(DEBUG_FULL, "Setting pendingnames to '%d' for client with fd '%d'.\n", channelcount, sourcefd);          clients[arrindex(clients, sourcefd)].pendingnames = channelcount;          // Get client to join channels, and tell client about those channels          for (int i = 0; i < channelcount; i++) { -          debugprint("JOINing channel[%d] out of %d.\n", i, channelcount); +          debugprint(DEBUG_FULL, "JOINing channel[%d] out of %d.\n", i, channelcount);            // Skip this one and increment channelcount if it's a blank channel            if (!channels[i].name[0]) { -              debugprint("Skipping channel[%d], incrementing channelcount.\n", i); +              debugprint(DEBUG_FULL, "Skipping channel[%d], incrementing channelcount.\n", i);                channelcount++;                continue;            } @@ -1735,14 +1755,14 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Pretty much ignore anything else the client says if it's not registered yet,        // as the first thing we want to hear is either PASS or USER        if (!clients[arrindex(clients, sourcefd)].registered) { -        debugprint("Ignoring client command '%s' from sourcefd '%d' as not registered yet.\n", tokens[0], sourcefd); +        debugprint(DEBUG_SOME, "Ignoring client command '%s' from sourcefd '%d' as not registered yet.\n", tokens[0], sourcefd);          free(strcopyPtr);          return 1;        }        // Client PING received?  If so, send a PONG back with the next element as the argument.        if (strncasecmp(tokens[0], "PING", strlen(tokens[0])) == 0) { -        debugprint("Client PING found and it is: %s with length %zd!  Sending response...\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client PING found and it is: %s with length %zd!  Sending response...\n", tokens[0], strlen(tokens[0]));          char outgoingmsg[MAXDATASIZE]; // String to send to client          if (!snprintf(outgoingmsg, MAXDATASIZE, "PONG %s", tokens[1])) { // TODO - Make sure tokens[1] actually has a token @@ -1758,14 +1778,14 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // TODO - Ignoring CAP for now so as not to confuse other clients, but we should probably query the server then relay the response to the client        if (strncasecmp(tokens[0], "CAP", strlen(tokens[0])) == 0) { -        debugprint("Client CAP found and it is: %s with length %zd!  Ignoring completely for now - TODO - do something useful!\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client CAP found and it is: %s with length %zd!  Ignoring completely for now - TODO - do something useful!\n", tokens[0], strlen(tokens[0]));          free(strcopyPtr);          return 1;        }        // Just send NICK to server and let it change all clients' nicks if needed        if (strncasecmp(tokens[0], "NICK", strlen(tokens[0])) == 0) { -        debugprint("Client NICK found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client NICK found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));          sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);          free(strcopyPtr);          return 1; @@ -1773,13 +1793,13 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // If PRIVMSG received, send to server, but also reformat and send to all other clients and log to replay file.        if (strncasecmp(tokens[0], "PRIVMSG", strlen(tokens[0])) == 0) { -        debugprint("Client PRIVMSG found and it is: %s with length %zd!  Sending to server then back to other clients...\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client PRIVMSG found and it is: %s with length %zd!  Sending to server then back to other clients...\n", tokens[0], strlen(tokens[0]));          // Send original request straight to server          sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);          // If it seems to be a CTCP VERSION request, just send to the server (CTCP requests are delimited with \1)          if (counter == 3 && strncmp(tokens[2], ":\1VERSION\1", strlen(tokens[2])) == 0) { -          debugprint("Client PRIVMSG looked like a CTCP VERSION request, so not sending to other clients.\n"); +          debugprint(DEBUG_FULL, "Client PRIVMSG looked like a CTCP VERSION request, so not sending to other clients.\n");            free(strcopyPtr);            return 1;          } @@ -1810,7 +1830,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Just send JOIN to server and let it talk back to clients as required        if (strncasecmp(tokens[0], "JOIN", strlen(tokens[0])) == 0) { -        debugprint("Client JOIN found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client JOIN found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));          sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);          free(strcopyPtr);          return 1; @@ -1819,7 +1839,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Don't do anything with QUIT, just let the client go - TODO: Let another clients know with a NOTICE or something        // A client has QUIT, so disconnect (close) them and don't do anything else for now - TODO: Let another clients know with a NOTICE or something        if (strncasecmp(tokens[0], "QUIT", strlen(tokens[0])) == 0) { -        debugprint("Client QUIT found from fd %d and it is: %s with length %zd!  Disconnecting that fd.\n", sourcefd, tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client QUIT found from fd %d and it is: %s with length %zd!  Disconnecting that fd.\n", sourcefd, tokens[0], strlen(tokens[0]));          disconnectclient(sourcefd, clients, ircdstrings, settings);          free(strcopyPtr);          return 1; @@ -1827,7 +1847,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Just send PART to server and let it talk back to clients as required        if (strncasecmp(tokens[0], "PART", strlen(tokens[0])) == 0) { -        debugprint("Client PART found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client PART found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));          sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);          free(strcopyPtr);          return 1; @@ -1835,7 +1855,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Just send TOPIC to server and let it talk back to clients as required        if (strncasecmp(tokens[0], "TOPIC", strlen(tokens[0])) == 0) { -        debugprint("Client TOPIC found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client TOPIC found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));          sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);          free(strcopyPtr);          return 1; @@ -1844,14 +1864,14 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Take note of what sort of MODE was requested, mark the client as waiting for the reply (so not all clients get it)        // Send it to the server either way and let it talk back to the requesting client as required        if (strncasecmp(tokens[0], "MODE", strlen(tokens[0])) == 0) { -        debugprint("Client MODE found and it is: %s with length %zd!  Analysing...\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client MODE found and it is: %s with length %zd!  Analysing...\n", tokens[0], strlen(tokens[0]));          // Is it a ban MODE request (MODE #channel b)?          if (counter >= 3 && strncmp(tokens[2], "b", strlen("b")) == 0) { -          debugprint("Ban MODE request received, marking as pending.\n"); +          debugprint(DEBUG_FULL, "Ban MODE request received, marking as pending.\n");            clients[arrindex(clients, sourcefd)].pendingban = 1;          } else if (counter == 2) {            // Assume a normal channel mode request (MODE #channel) - TODO - What if it isn't!? -          debugprint("Assuming channel MODE request received, marking as pending.\n"); +          debugprint(DEBUG_FULL, "Assuming channel MODE request received, marking as pending.\n");            clients[arrindex(clients, sourcefd)].pendingchannelmode = 1;          } @@ -1863,7 +1883,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // WHO requested, mark the client as waiting for the reply (so not all clients get it) and send it on the server        if (strncasecmp(tokens[0], "WHO", strlen(tokens[0])) == 0) { -        debugprint("Client WHO found and it is: %s with length %zd!  Marking as pending.\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client WHO found and it is: %s with length %zd!  Marking as pending.\n", tokens[0], strlen(tokens[0]));          clients[arrindex(clients, sourcefd)].pendingwho = 1;          // Either way, send it on the server @@ -1874,7 +1894,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // LIST requested, mark the client as waiting for the reply (so not all clients get it) and send it on the server        if (strncasecmp(tokens[0], "LIST", strlen(tokens[0])) == 0) { -        debugprint("Client LIST found and it is: %s with length %zd!  Marking as pending.\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client LIST found and it is: %s with length %zd!  Marking as pending.\n", tokens[0], strlen(tokens[0]));          clients[arrindex(clients, sourcefd)].pendinglist = 1;          // Either way, send it on the server @@ -1885,7 +1905,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Client WHOIS received, send straight on to server and mark the client as pending the response        if (strncasecmp(tokens[0], "WHOIS", strlen(tokens[0])) == 0) { -        debugprint("Client WHOIS found and it is: %s with length %zd!  Sending to server and setting client as pending.\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client WHOIS found and it is: %s with length %zd!  Sending to server and setting client as pending.\n", tokens[0], strlen(tokens[0]));          clients[arrindex(clients, sourcefd)].pendingwhois = 1;          sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);          free(strcopyPtr); @@ -1894,7 +1914,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Client WHOWAS received, send straight on to server and mark the client as pending the response        if (strncasecmp(tokens[0], "WHOWAS", strlen(tokens[0])) == 0) { -        debugprint("Client WHOWAS found and it is: %s with length %zd!  Sending to server and setting client as pending.\n", tokens[0], strlen(tokens[0])); +        debugprint(DEBUG_FULL, "Client WHOWAS found and it is: %s with length %zd!  Sending to server and setting client as pending.\n", tokens[0], strlen(tokens[0]));          clients[arrindex(clients, sourcefd)].pendingwhowas = 1;          sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);          free(strcopyPtr); @@ -1924,7 +1944,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli          // If it's a CTCP VERSION response then only send to the server (CTCP requests are delimited with \1)          if (counter >= 3 && strncmp(tokens[2], ":\1VERSION", strlen(tokens[2])) == 0) { -          debugprint("Client NOTICE looked like a CTCP VERSION response, so just sending to the server.\n"); +          debugprint(DEBUG_FULL, "Client NOTICE looked like a CTCP VERSION response, so just sending to the server.\n");            sendtoserver(server_ssl, str, strlen(str), sourcefd, clients, settings);            free(strcopyPtr);            return 1; @@ -1937,10 +1957,10 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli        // Case insensitive comparisons here since clients won't be recognising and uppercasing these commands        if (strncasecmp(tokens[0], "BLABOUNCER", strlen(tokens[0])) == 0) {          char outgoingmsg[MAXDATASIZE]; -        debugprint("Client BLABOUNCER found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1])); +        debugprint(DEBUG_FULL, "Client BLABOUNCER found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1]));          // REPLAY received, send the requested length of replay time to the client          if (strncasecmp(tokens[1], "REPLAY", strlen("REPLAY")) == 0) { -          debugprint("Client BLABOUNCER REPLAY (custom blabouncer command) found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_FULL, "Client BLABOUNCER REPLAY (custom blabouncer command) found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1]));            // Split the request into days:hours:minutes:seconds @@ -1958,7 +1978,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            while ((timetoken = strsep(×trcopy, ":")) != NULL) {              if (*timetoken == '\0') continue; // Skip consecutive matches              if (timecounter >= MAXTOKENS) break; // Too many tokens -            debugprint("Time token: \"%s\", length %zd.\n", timetoken, strlen(timetoken)); +            debugprint(DEBUG_FULL, "Time token: \"%s\", length %zd.\n", timetoken, strlen(timetoken));              // Copy into the token array (strlen + 1 to get the NULL terminator)              strncpy(timetokens[timecounter], timetoken, strlen(timetoken) + 1);              timecounter++; @@ -1966,7 +1986,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            // Make sure we don't have more than four (d:h:m:s) components            if (timecounter > 4) { -            debugprint("Too many time components requested by REPLAY command.  Telling client.\n"); +            debugprint(DEBUG_SOME, "Too many time components requested by REPLAY command.  Telling client.\n");              snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Too many time components requestd by REPLAY command.  Expected up to four (days:hours:minutes:seconds).", ircdstrings->ircnick);              sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);              free(timestrcopyPtr); @@ -1982,7 +2002,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              errno = 0;              check = strtol(timetokens[i], &str_end, 10);              if (str_end == timetokens[i] || ((check == LONG_MAX || check == LONG_MIN) && errno == ERANGE)) { -              debugprint("Invalid number '%s' requested by REPLAY command.  Telling client.\n", timetokens[i]); +              debugprint(DEBUG_SOME, "Invalid number '%s' requested by REPLAY command.  Telling client.\n", timetokens[i]);                if (!snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Invalid number '%s' requested by REPLAY command.", ircdstrings->ircnick, timetokens[i])) {                  fprintf(stderr, "Error while preparing REPLAY invalid number response!\n");                  exit(1); @@ -2020,7 +2040,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              replayseconds += strtol(timetokens[0], NULL, 10);            } -          debugprint("Replaying '%s' which is '%d' seconds.\n", tokens[2], replayseconds); +          debugprint(DEBUG_FULL, "Replaying '%s' which is '%d' seconds.\n", tokens[2], replayseconds);            if (!doreplay(sourcefd, replayseconds, clients, settings, ircdstrings, channels)) {              snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Unable to read replay log file!", ircdstrings->ircnick); @@ -2031,7 +2051,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli            return 1;          // QUIT received, send QUIT message to server and exit cleanly          } else if (strncasecmp(tokens[1], "QUIT", strlen("QUIT")) == 0) { -          debugprint("Client QUIT found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_SOME, "Client BLABOUNCER QUIT found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1]));            snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Exiting on BLABOUNCER QUIT command from client with fd '%d'.", ircdstrings->ircnick, sourcefd);            sendtoallclients(clients, outgoingmsg, EXCEPT_NONE, settings);            // Combine "QUIT :" with any optional quit message the user provided @@ -2043,12 +2063,12 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli              snprintf(quitmsg, MAXDATASIZE, "QUIT");            }            sendtoserver(server_ssl, quitmsg, strlen(quitmsg), sourcefd, clients, settings); -          debugprint("Exiting on client request.\n"); +          debugprint(DEBUG_CRIT, "Exiting on client request.\n");            free(strcopyPtr);            exit(0);          // Unrecognised BLABOUNCER command received, send some help instructions          } else { -          debugprint("Client BLABOUNCER unrecognised command found and it is: %s with length %zd!  Sending a help message.\n", tokens[1], strlen(tokens[1])); +          debugprint(DEBUG_SOME, "Client BLABOUNCER unrecognised command found and it is: %s with length %zd!  Sending a help message.\n", tokens[1], strlen(tokens[1]));            snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Unrecognised BLABOUNCER command received.  Valid commands are:", ircdstrings->ircnick);            sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);            snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [[[[days:]hours:]minutes:]seconds]\" (To replay a given length of time of replay log.)", ircdstrings->ircnick); @@ -2068,7 +2088,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli    // =============================================> -  debugprint("Done with processircmessage()\n"); +  debugprint(DEBUG_FULL, "Done with processircmessage()\n");    // If we got here then we didn't process anything    free(strcopyPtr); @@ -2096,7 +2116,7 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie    // Keep track of initial pointer for free()ing later    char *strcopyPtr = strcopy; -  debugprint("processrawstring(): Source type %d sent: \"%s\".  Processing it...\n", source, strcopy); +  debugprint(DEBUG_FULL, "processrawstring(): Source type %d sent: \"%s\".  Processing it...\n", source, strcopy);    // Track which CLRF-separated message within this string we're on    int messagecount = 0; @@ -2110,7 +2130,7 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie    while ((token = strsep(&strcopy, "\r\n")) != NULL) {      if (*token == '\0') continue; // Skip consecutive matches      if (messagecount >= MAXTOKENS) break; // Too many tokens -    debugprint("String Token: \"%s\", length %zd.\n", token, strlen(token)); +    debugprint(DEBUG_FULL, "String Token: \"%s\", length %zd.\n", token, strlen(token));      // Copy into the token array (strlen + 1 to get the NULL terminator)      strncpy(messages[messagecount], token, strlen(token) + 1);      messagecount++; @@ -2123,10 +2143,10 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie    if (ircdstrings->currentmsg[0] && source == SOURCE_SERVER) {      // Make a copy since we can't have source and destination the same with snprintf      char *strtmp = strdup(messages[0]); -    debugprint("processrawstring(): Previous truncated message detected, combining old '%s' with new '%s'...\n", ircdstrings->currentmsg, strtmp); +    debugprint(DEBUG_FULL, "processrawstring(): Previous truncated message detected, combining old '%s' with new '%s'...\n", ircdstrings->currentmsg, strtmp);      snprintf(messages[0], strlen(ircdstrings->currentmsg) + strlen(strtmp) + 1, "%s%s", ircdstrings->currentmsg, strtmp);      messages[0][strlen(ircdstrings->currentmsg) + strlen(strtmp)] = '\0'; // Make sure it's null terminated -    debugprint("...into new string '%s' and clearing currentmsg holding area.\n", messages[0]); +    debugprint(DEBUG_FULL, "...into new string '%s' and clearing currentmsg holding area.\n", messages[0]);      ircdstrings->currentmsg[0] = '\0';      free(strtmp);    } @@ -2135,7 +2155,7 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie    // Copy to a holding area for continuation next time    // (Only if source was the server since we always strip \r\n from client messages when recving - TODO - Should we be doing that?    if ((str[strlen(str)-2] != 13 || str[strlen(str)-1] != 10) && source == SOURCE_SERVER) { -    debugprint("processrawstring(): Truncated message detected, storing final token '%s' for later.\n", messages[messagecount - 1]); +    debugprint(DEBUG_FULL, "processrawstring(): Truncated message detected, storing final token '%s' for later.\n", messages[messagecount - 1]);      strncpy(ircdstrings->currentmsg, messages[messagecount - 1], strlen(messages[messagecount - 1]));      ircdstrings->currentmsg[strlen(messages[messagecount - 1])] = '\0';      // Remove it from the message count so it's not processed time time @@ -2150,7 +2170,7 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie      // Copy to a temporary string so we still have the original in case it's not processed      char *messagecopy = strdup(messages[i]);      if (processircmessage(server_ssl, messagecopy, source, clients, sourcefd, ircdstrings, channels, settings)) { -      debugprint("Message processed: \"%s\", NULLing...\n", messages[i]); +      debugprint(DEBUG_FULL, "Message processed: \"%s\", NULLing...\n", messages[i]);        messages[i][0] = '\0';      }      free(messagecopy); @@ -2159,20 +2179,20 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie    // Deal with any unprocessed messages (send on to server/client(s) since we haven't dealt with them)    for (int i = 0; i < messagecount; i++) {      if (messages[i][0] != '\0') { -      debugprint("Message %d (\"%s\") remains unprocessed...\n", i, messages[i]); +      debugprint(DEBUG_FULL, "Message %d (\"%s\") remains unprocessed...\n", i, messages[i]);        switch(source) {          case SOURCE_SERVER: // If message(s) were from the real IRC server            // Relay/send to all clients ("except" = 0 because this should send to all clients)            // TODO - Is this really going to send the original string if we have messed it with it in processrawstring() and friends!? -          debugprint("bouncer-server: sending unprocessed server message \"%s\" to all clients, length %zd.\n", messages[i], strlen(messages[i])); +          debugprint(DEBUG_FULL, "bouncer-server: sending unprocessed server message '%s' to all clients, length %zd.\n", messages[i], strlen(messages[i]));            sendtoallclients(clients, messages[i], EXCEPT_NONE, settings);            break;          case SOURCE_CLIENT: // If message(s) were from a real IRC client            // Send to server -          debugprint("bouncer-client: sending unprocessed client message \"%s\" to the server, length %zd.\n", messages[i], strlen(messages[i])); +          debugprint(DEBUG_FULL, "bouncer-client: sending unprocessed client message '%s' to the server, length %zd.\n", messages[i], strlen(messages[i]));            sendtoserver(server_ssl, messages[i], strlen(messages[i]), sourcefd, clients, settings); -          debugprint("bouncer-client: sending unprocessed client message \"%s\" to all other clients, length %zd.\n", messages[i], strlen(messages[i])); +          debugprint(DEBUG_FULL, "bouncer-client: sending unprocessed client message '%s' to all other clients, length %zd.\n", messages[i], strlen(messages[i]));            // send the same thing to all *other* clients (all except for source fd)            sendtoallclients(clients, messages[i], sourcefd, settings);            break; @@ -2183,7 +2203,7 @@ int processrawstring(SSL *server_ssl, char *str, int source, struct client *clie      }    } -  debugprint("Done with processrawstring()\n"); +  debugprint(DEBUG_FULL, "Done with processrawstring()\n");    return 1;  } @@ -2259,7 +2279,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {    }    while (1) { -    debugprint("top of loop, fdmax %d.\n", fdmax); +    debugprint(DEBUG_FULL, "top of loop, fdmax %d.\n", fdmax);      FD_ZERO(&rfds); // clear entries from fd set      FD_SET(STDIN, &rfds); // add STDIN (fd 0) to read fds to monitor @@ -2271,7 +2291,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {      // TODO - now that only connected clients are monitored, perhaps tracking using both fdmax and num_client loops is unnecessary?      for (int i = 0; i < MAXCLIENTS; i++) {        if (clients[i].fd > 0) { -        debugprint("monitoring fd %d.\n", clients[i].fd); +        debugprint(DEBUG_FULL, "monitoring fd %d.\n", clients[i].fd);          FD_SET(clients[i].fd, &rfds);        }      } @@ -2303,7 +2323,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {        continue;      } -    debugprint("select()ing...\n"); +    debugprint(DEBUG_FULL, "select()ing...\n");      // check to see if anything in the fd_set is waiting - waits here until one of the fds in the set does something      if (select(fdmax + 1, &rfds, NULL, NULL, NULL) < 0) { // network socket + 1, rfds, no writes, no exceptions/errors, no timeout        printf("receive error, exiting!?\n"); @@ -2315,14 +2335,16 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {      // See if there's anything to read from the server side (the real IRCd)      if (FD_ISSET(*serversockfd, &rfds)) { -      debugprint("reading server socket!\n"); +      debugprint(DEBUG_FULL, "reading server socket!\n");        if ((servernumbytes = sockread(server_ssl, serverbuf, MAXRCVSIZE - 1, settings->servertls)) == -1) {          printf("receive error (-1), exiting...\n");          perror("recv"); +        debugprint(DEBUG_CRIT, "serversockfd receive error (-1), errno '%d'.\n");        } else if (servernumbytes == 0) {          printf("socket closed (or no data received) (0), exiting...\n");          perror("recv"); +        debugprint(DEBUG_CRIT, "serversockfd socket closed (or no data received) (0), errno '%d'.\n");        }        // If there was a socket error (receive error or socket closed) @@ -2354,7 +2376,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {        serverbuf[servernumbytes] = '\0'; -      debugprint("BOUNCER-SERVER RECEIVED: '%s', length '%d'.\n", serverbuf, servernumbytes); +      debugprint(DEBUG_SOME, "BOUNCER-SERVER RECEIVED: '%s', length '%d'.\n", serverbuf, servernumbytes);        // Try to process received string (which should contain one or more server responses/commands)        // TODO - What if there were two server respones/commands and only one didn't need relaying? @@ -2366,7 +2388,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {      // see if there's anything from stdin      if (FD_ISSET(STDIN, &rfds)) { -      debugprint("reading stdin!\n"); +      debugprint(DEBUG_FULL, "reading stdin!\n");        char outgoingmsg[MAXDATASIZE]; // String to send to server        int outgoingmsgrc; // Return code from getstdin() for outgoing message @@ -2389,7 +2411,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {            printf("Checking channel[%d] out of %d.\n", i, channelcount);            // Skip this one and increment channelcount if it's a blank channel            if (!channels[i].name[0]) { -              debugprint("Skipping channel[%d], incrementing channelcount.\n", i); +              debugprint(DEBUG_FULL, "Skipping channel[%d], incrementing channelcount.\n", i);                channelcount++;                continue;            } @@ -2413,12 +2435,12 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {        if (i == newfd) {          continue;        } -      debugprint("checking client socket %d out of %d.\n", i, fdmax); +      debugprint(DEBUG_FULL, "checking client socket %d out of %d.\n", i, fdmax);        if (FD_ISSET(i, &rfds)) { -        debugprint("fd %d is FD_ISSET and it is a...\n", i); +        debugprint(DEBUG_FULL, "fd %d is FD_ISSET and it is a...\n", i);          // if value of clientsockfd then must be a new connection, if greater must be an existing connection          if (i == *clientsockfd) { -          debugprint("...new connection!\n"); +          debugprint(DEBUG_SOME, "...new connection!\n");            // handle new connections            if (numclients(clients) >= MAXCLIENTS) {              fprintf(stderr, "too many clients!\n"); @@ -2446,10 +2468,10 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {                      clients[j].ssl = SSL_new(ctx);                      SSL_set_fd(clients[j].ssl, newfd);                      if (SSL_accept(clients[j].ssl) <= 0) { -                      printf("SSL_accept failed for fd %d.\n", clients[j].fd); +                      debugprint(DEBUG_CRIT, "SSL_accept failed for fd %d.\n", clients[j].fd);                        ERR_print_errors_fp(stderr);                      } else { -                      debugprint("SSL_accept succeeded for fd %d.\n", clients[j].fd); +                      debugprint(DEBUG_FULL, "SSL_accept succeeded for fd %d.\n", clients[j].fd);                      }                    } else {                      // If not using TLS then cast newfd to SSL* even though it will just be the original newfd int really @@ -2459,7 +2481,9 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {                  }              }              // TODO - Handle the "find a free element" loop not finding a free element -            debugprint("bouncer-client: new connection from %s on socket %d\n", inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), remoteIP, INET6_ADDRSTRLEN), newfd); +            debugprint(DEBUG_FULL, "bouncer-client: new connection from %s on socket %d\n", +                       inet_ntop(remoteaddr.ss_family, get_in_addr((struct sockaddr*)&remoteaddr), +                       remoteIP, INET6_ADDRSTRLEN), newfd);              // Alert other clients about the new connection              char alertmsg[MAXDATASIZE];              if (!snprintf(alertmsg, MAXDATASIZE, "NOTICE %s :blabouncer: new client connected from %s with fd %d.", ircdstrings.ircnick, @@ -2469,24 +2493,25 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {              }              // "except" 0 since we trust this message              sendtoallclients(clients, alertmsg, 0, settings); -            debugprint("bouncer-client: total client connections: %d\n", numclients(clients)); +            debugprint(DEBUG_FULL, "bouncer-client: total client connections: %d\n", numclients(clients));            }          } else { -          debugprint("...previous connection!\n"); +          debugprint(DEBUG_FULL, "...previous connection!\n");            // handle data from a client            if ((clientnumbytes = sockread(clients[arrindex(clients, i)].ssl, clientbuf, sizeof clientbuf, settings->clienttls)) <= 0) {              // got error or connection closed by client              if (clientnumbytes == 0) {                // connection closed -              debugprint("bouncer-client: socket %d hung up\n", i); +              debugprint(DEBUG_SOME, "bouncer-client: socket %d hung up\n", i);              } else {                perror("recv"); +              debugprint(DEBUG_CRIT, "bouncer-client: socket error, clientnum bytes '%d', errno '%d'.\n", clientnumbytes, errno);              }              // Disconnect the client              disconnectclient(i, clients, &ircdstrings, settings);              FD_CLR(i, &rfds); // remove from master set - TODO is this needed at the moment since we just add everything from *clientsockfd to fdmax to rfds              // TODO - Handle the "remove the client" loop not finding the old fd -            debugprint("bouncer-client: total client connections: %d\n", numclients(clients)); +            debugprint(DEBUG_FULL, "bouncer-client: total client connections: %d\n", numclients(clients));            } else {              // we got some data from a client              // null terminate that baby @@ -2495,7 +2520,7 @@ void dochat(int *serversockfd, int *clientsockfd, struct settings *settings) {              while (clientbuf[strlen(clientbuf) - 1] == '\n' || clientbuf[strlen(clientbuf) - 1] == '\r') {                clientbuf[strlen(clientbuf) - 1] = '\0';              } -            debugprint("BOUNCER-CLIENT RECEIVED: '%s'\n", clientbuf); +            debugprint(DEBUG_SOME, "BOUNCER-CLIENT RECEIVED: '%s'\n", clientbuf);              // Try to process received string (which should contain one or more client responses/commands)              // TODO - What if there were two server respones/commands and only one didn't need relaying? @@ -2516,6 +2541,9 @@ int main(int argc, char *argv[]) {    // Structure of our various settings which are to either be read from the configuration file or set at runtime    struct settings settings; +  // Terminate our global debug file string in case it's referenced before being read from file +  debugpath[0] = '\0'; +    // Check to see if a configuration file was specified on the command line    if (argc == 3) {      if (strcmp(argv[1], "-c")) { @@ -2539,9 +2567,7 @@ int main(int argc, char *argv[]) {      }    } -  debugprint("Using configuration file '%s'.\n", settings.conffile); - -  // Populate said settings from configuration file +  // Populate settings from configuration file    // How many seconds of replay log should automatically be replayed - TODO - Can we do error checking on this?    settings.replayseconds = getconfint("replayseconds", settings.conffile); @@ -2712,10 +2738,12 @@ int main(int argc, char *argv[]) {    // Temporarily enable debugging to file    debug = 1;    // Print it -  debugprint("blabouncer started at %s, debugging is set to %d.\n", timestr, debugold); +  debugprint(DEBUG_CRIT, "blabouncer started at %s, debugging is set to %d.\n", timestr, debugold);    // Set debugging back to whatever it was    debug = debugold; +  debugprint(DEBUG_SOME, "Using configuration file '%s'.\n", settings.conffile); +    // TODO: see if any of this can be shared (i.e. 1. avoid code duplication, and 2. see if variables can be shared between client/server sockets)    // I will try to keep to the notation of "server" meaning the real IRCd, "bouncer" meaning the bouncer, and "client" meaning the real IRC client diff --git a/blabouncer.conf.example b/blabouncer.conf.example index 6fd5c7a..dd98c72 100644 --- a/blabouncer.conf.example +++ b/blabouncer.conf.example @@ -66,6 +66,6 @@ logging = "1"  # Replay log goes to basedir/replay.log  replaylogging = "1" -# Debug output control ("2" for print to screen, "1" for print to file, or "0" for disabled) -# (The debug file can be found in <basedir>/debug.txt) -debug = "1" +# Debug verbosity ("0" for critical only, "1" for some extra info, "2" for full debug mode) +# (All output goes to <basedir>/debug.txt) +debug = "2" @@ -48,7 +48,7 @@ int getconfstr(char *confname, char *filename, char* dest) {    // If we got here, then either we found the configuration option or we ran out of file    if (!found) { -    debugprint("Error reading configuration option '%s', did not find it in configuration file '%s'.\n", confname, filename); +    debugprint(DEBUG_SOME, "Error reading configuration option '%s', did not find it in configuration file '%s'.\n", confname, filename);      fclose(fp);      return 0;    } @@ -80,7 +80,7 @@ int getconfstr(char *confname, char *filename, char* dest) {    strncpy(dest, conf + 1, strlen(conf) - 2); // Copy result to destination string without quotes    dest[strlen(conf) - 2] = '\0'; // Null terminate -  debugprint("getconfstr(): returning '%s'.\n", dest); +  debugprint(DEBUG_FULL, "getconfstr(): returning '%s'.\n", dest);    // Close fine and return success    fclose(fp); @@ -107,21 +107,21 @@ int checkpassword(char *password, char *filename) {    char confpassword[MAXCHAR];    if (!getconfstr("password", filename, confpassword)) { -    debugprint("checkpassword(): error getting configuration option 'password' from configuration file '%s'.\n", filename); +    debugprint(DEBUG_CRIT, "checkpassword(): error getting configuration option 'password' from configuration file '%s'.\n", filename);      return 0;    }    // Ensure passwords are the same length    if (strlen(password) != strlen(confpassword)) { -    debugprint("Password length mismatch!\n"); +    debugprint(DEBUG_SOME, "Password length mismatch!\n");      return 0;    }    // Ensure passwords match    if (strncmp(password, confpassword, strlen(password)) == 0) { -    debugprint("confpassword matches password.\n"); +    debugprint(DEBUG_FULL, "confpassword matches password.\n");      return 1;    } else { -    debugprint("confpassword does NOT match password!\n"); +    debugprint(DEBUG_SOME, "confpassword does NOT match password!\n");      return 0;    } @@ -227,9 +227,9 @@ int createconfigfile(char *filename) {    "# Replay log goes to basedir/replay.log\n"    "replaylogging = \"1\"\n"    "\n" -  "# Debug output control (\"2\" for print to screen, \"1\" for print to file, or \"0\" for disabled)\n" -  "# (The debug file can be found in <basedir>/debug.txt)\n" -  "debug = \"1\"\n"; +  "# Debug verbosity (\"0\" for critical only, \"1\" for some extra info, \"2\" for full debug mode)\n" +  "# (All output goes to <basedir>/debug.txt)\n" +  "debug = \"2\"\n";    // Write complete string to file    if ((fprintf(fp, "%s", string)) < 0) { @@ -10,6 +10,10 @@  #include "functions.h" +#define DEBUG_CRIT 0 +#define DEBUG_SOME 1 +#define DEBUG_FULL 2 +  #define MAXCHAR 1000  // Sets 'dest' to the value of the configuration option with name diff --git a/functions.c b/functions.c index 0c814a3..13b910b 100644 --- a/functions.c +++ b/functions.c @@ -8,7 +8,7 @@ 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("updategreetingnick(): '%s' '%s' '%s' '%s'.\n", greeting, greetingnum, newnick, 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]; @@ -27,13 +27,14 @@ void updategreetingnick(char *greeting, char *greetingnum, char *newnick, char *      snprintf(searchstr, MAXDATASIZE, " %s %s ", greetingnum, newnick);      ret = strstr(greeting, searchstr);      if (ret != NULL) { -      debugprint("updategreetingnick(): newnick is already present, returning.\n"); +      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);    } @@ -57,29 +58,32 @@ void updategreetingnick(char *greeting, char *greetingnum, char *newnick, char *    // And finally copy back to source string    strcpy(greeting, greetingtmp2); -  debugprint("updategreetingnick(): Built new greeting '%s' '%s', length '%ld'.\n", greetingnum, greeting, strlen(greeting)); +  debugprint(DEBUG_FULL, "updategreetingnick(): Built new greeting '%s' '%s', length '%ld'.\n", greetingnum, greeting, strlen(greeting));  } -// Print debugging output if enabled -// (To screen or to file depending on settings) -void debugprint(char *format, ...) { -  if (debug == DEBUG_NONE) return; +// 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); -  if (debug == DEBUG_FILE) { -    FILE *fp; -    int bytes = 0; -    fp = fopen(debugpath, "a"); -    if ((bytes = vfprintf(fp, format, args)) < 0) { -      printf("error: could not write to debug file.\n"); -      exit(1); -    } -    fclose(fp); -  } else if (debug == DEBUG_SCREEN) { -    vprintf(format, args); +  FILE *fp; +  int bytes = 0; +  fp = fopen(debugpath, "a"); +  if ((bytes = vfprintf(fp, format, args)) < 0) { +    printf("error: could not write to debug file.\n"); +    exit(1);    } +  fclose(fp);    va_end(args);  } @@ -135,11 +139,11 @@ void stripprefix(char *string) {    // Make a copy to work with    char string2[strlen(string)]; -  debugprint("stripprefix(): starting with '%s', strlen: %zd.\n", string, 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("stripprefix(): no leading ':', returning.\n"); +    debugprint(DEBUG_FULL, "stripprefix(): no leading ':', returning.\n");      return;    } @@ -154,7 +158,7 @@ void stripprefix(char *string) {    // Finish with null terminator    string[strlen(string) - 1] = '\0'; -  debugprint("stripprefix(): finishing with '%s', strlen: %zd.\n", string, strlen(string)); +  debugprint(DEBUG_FULL, "stripprefix(): finishing with '%s', strlen: %zd.\n", string, strlen(string));  }  // Extract final parameter from IRC message, removing the leading colon ':' @@ -169,7 +173,7 @@ void extractfinalparameter(char *string) {    // Position of colon    int colonpos = -1; -  debugprint("extractfinalparameter(): starting with '%s', strlen: %zd.\n", string, strlen(string)); +  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); @@ -177,14 +181,14 @@ void extractfinalparameter(char *string) {    // Find the colon    for (size_t i = 0; i < strlen(string); i++) {      if (string[i] == ':') { -      debugprint("Found colon at position %zd!\n", i); +      debugprint(DEBUG_FULL, "Found colon at position %zd!\n", i);        colonpos = i;        break;      }    }    if (colonpos == -1) { -    debugprint("no colon found, returning\n"); +    debugprint(DEBUG_FULL, "no colon found, returning\n");      return;    } @@ -201,7 +205,7 @@ void extractfinalparameter(char *string) {    // Finish with null terminator    string[counter] = '\0'; -  debugprint("extractfinalparameter(): finishing with '%s', strlen: %zd.\n", string, strlen(string)); +  debugprint(DEBUG_FULL, "extractfinalparameter(): finishing with '%s', strlen: %zd.\n", string, strlen(string));  }  // Extract the IRC nick from a prefix @@ -213,7 +217,7 @@ void extractnickfromprefix(char *string) {    // Position of bang    int bangpos = -1; -  debugprint("extractnickfromprefix(): starting with '%s', strlen: %zd.\n", string, strlen(string)); +  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); @@ -221,26 +225,26 @@ void extractnickfromprefix(char *string) {    // Find the bang    for (size_t i = 0; i < strlen(string); i++) {      if (string[i] == '!') { -      debugprint("Found bang at position %zd!\n", i); +      debugprint(DEBUG_FULL, "Found bang at position %zd!\n", i);        bangpos = i;        break;      }    }    if (bangpos == -1) { -    debugprint("no bang found, returning\n"); +    debugprint(DEBUG_FULL, "no bang found, returning\n");      return;    }    // Terminate the string at whatever position we found the bang    string[bangpos] = '\0'; -  debugprint("extractnickfromprefix(): finishing with '%s', strlen: %zd.\n", string, strlen(string)); +  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("updatenickuserhost(): updating '%s' with '%s'.\n", nickuserhost, nick); +  debugprint(DEBUG_FULL, "updatenickuserhost(): updating '%s' with '%s'.\n", nickuserhost, nick);    // Position of bang    int bangpos = -1; @@ -248,14 +252,14 @@ void updatenickuserhost(char *nickuserhost, char *nick) {    // Find the bang    for (size_t i = 0; i < strlen(nickuserhost); i++) {      if (nickuserhost[i] == '!') { -      debugprint("Found bang at position %ld!\n", i); +      debugprint(DEBUG_FULL, "Found bang at position %ld!\n", i);        bangpos = i;        break;      }    }    if (bangpos == -1) { -    debugprint("No bang found in existing nickuserhost, quitting!\n"); +    debugprint(DEBUG_FULL, "No bang found in existing nickuserhost, quitting!\n");      return;    } @@ -267,12 +271,13 @@ void updatenickuserhost(char *nickuserhost, char *nick) {    // Copy back to source string    strcpy(nickuserhost, newstr); -  debugprint("updatenickuserhost(): new nickuserhost '%s', length '%ld'.\n", nickuserhost, strlen(nickuserhost)); +  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("updategreetings(): updating greetings with new nickuserhost '%s' and nick '%s'.\n", newnickuserhost, newnick); +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" @@ -303,7 +308,7 @@ void updategreetings(char *greeting001, char *greeting002, char *greeting003, ch    // Copy back to source greeting 001    strcpy(greeting001, greetingtmp); -  debugprint("updategreetings(): new greeting 001 '%s', length '%ld'.\n", greeting001, strlen(greeting001)); +  debugprint(DEBUG_FULL, "updategreetings(): new greeting 001 '%s', length '%ld'.\n", greeting001, strlen(greeting001));    // Get the new nick diff --git a/functions.h b/functions.h index d56a295..dc3c4c3 100644 --- a/functions.h +++ b/functions.h @@ -21,12 +21,15 @@  #define OK       0  #define NO_INPUT 1  #define TOO_LONG 2 -#define DEBUG_NONE 0 -#define DEBUG_FILE 1 -#define DEBUG_SCREEN 2 -// Print debugging output if enabled -void debugprint(char *format, ...); +#define DEBUG_CRIT 0 +#define DEBUG_SOME 1 +#define DEBUG_FULL 2 + +// 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, ...);  // Get stdin line with buffer overrun protection  int getstdin(char *prompt, char *buff, size_t sz); @@ -57,7 +57,7 @@ int logline(char *str, char *ournick, char *basedir, int type) {      }      // Copy into the token array (strlen + 1 to get the NULL terminator)      strncpy(tokens[i], token, strlen(token) + 1); -    debugprint("logline(): extracted '%s'.\n", tokens[i]); +    debugprint(DEBUG_FULL, "logline(): extracted '%s'.\n", tokens[i]);    }    switch(type) { @@ -77,7 +77,7 @@ int logline(char *str, char *ournick, char *basedir, int type) {          snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]);        } -      debugprint("logline(): Logging PRIVMSG from '%s' to '%s' message '%s' in filename '%s'.\n", tokens[0], tokens[2], str, filename); +      debugprint(DEBUG_FULL, "logline(): Logging PRIVMSG from '%s' to '%s' message '%s' in filename '%s'.\n", tokens[0], tokens[2], str, filename);        break; @@ -97,7 +97,7 @@ int logline(char *str, char *ournick, char *basedir, int type) {        snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2] + pos); -      debugprint("logline(): Logging JOIN/PART to/from '%s' in filename '%s'.\n", tokens[2] + pos, filename); +      debugprint(DEBUG_FULL, "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") @@ -136,7 +136,7 @@ int logline(char *str, char *ournick, char *basedir, int type) {        snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]); -      debugprint("logline(): Logging TOPIC for '%s' in filename '%s'.\n", tokens[2], filename); +      debugprint(DEBUG_FULL, "logline(): Logging TOPIC for '%s' in filename '%s'.\n", tokens[2], filename);        // Build a friendly message (e.g. ":nick!user@host TOPIC #channel :blah blah" -> "nick has changed the topic to: blah blah")        snprintf(line, MAXCHAR, "%s has changed the topic to: %s", tokens[0], str); @@ -154,10 +154,11 @@ int logline(char *str, char *ournick, char *basedir, int type) {    struct stat st = {0};    if (stat(logdir, &st) == -1) {      if (mkdir(logdir, 0700)) { +      debugprint(DEBUG_CRIT, "Error creating log directory '%s.\n", logdir);        printf("Error creating log directory '%s'.\n", logdir);        exit(1);      } else { -      debugprint("logline(): log directory '%s'.\n", logdir); +      debugprint(DEBUG_FULL, "logline(): log directory '%s'.\n", logdir);      }    } @@ -168,6 +169,7 @@ int logline(char *str, char *ournick, char *basedir, int type) {    fp = fopen(filename, "a");    if (fp == NULL) { +    debugprint(DEBUG_CRIT, "error: could not open log file '%s' for writing.\n", filename);      printf("error: could not open log file '%s' for writing.\n", filename);      exit(1);    } @@ -202,10 +204,11 @@ int logline(char *str, char *ournick, char *basedir, int type) {    // Ensure the line finishes with CRLF    appendcrlf(line); -  debugprint("logline(): Complete log string to write: '%s', length '%ld'.\n", line, strlen(line)); +  debugprint(DEBUG_FULL, "logline(): Complete log string to write: '%s', length '%ld'.\n", line, strlen(line));    // Write complete line to file    if ((bytes = fprintf(fp, "%s", line)) < 0) { +    debugprint(DEBUG_CRIT, "error: could not write to log file.\n");      printf("error: could not write to log file.\n");      exit(1);    } @@ -19,6 +19,9 @@  #define LOG_PRIVMSG 0  #define LOG_JOINPART 1  #define LOG_TOPIC 2 +#define DEBUG_CRIT 0 +#define DEBUG_SOME 1 +#define DEBUG_FULL 2  // Write the line 'str' to the relevant log file such as  // '#channel.log' or 'nickname.log'.  'ournick' is our own @@ -199,7 +199,7 @@ int readreplayline(int seconds, int linenum, char *str, char *basedir) {    fp = fopen(filename, "r");    if (fp == NULL) { -    debugprint("error: could not open replay log '%s'.\n", filename); +    debugprint(DEBUG_CRIT, "error: could not open replay log '%s'.\n", filename);      fclose(fp);      return 0;    } @@ -211,7 +211,7 @@ int readreplayline(int seconds, int linenum, char *str, char *basedir) {      // Read the timestamp from each line      int timestamp = gettimestamp(line);      if (timestamp < 1) { -      debugprint("Error reading timestamp from replay log file.\n"); +      debugprint(DEBUG_CRIT, "Error reading timestamp from replay log file.\n");        fclose(fp);        return 0;      } @@ -257,7 +257,7 @@ int writereplayline(char *str, char *basedir) {    fp = fopen(filename, "a");    if (fp == NULL) { -    debugprint("error: could not open replay log '%s' for writing.\n", filename); +    debugprint(DEBUG_CRIT, "error: could not open replay log '%s' for writing.\n", filename);      fclose(fp);      return 0;    } @@ -274,11 +274,11 @@ int writereplayline(char *str, char *basedir) {    // Ensure the line finishes with CRLF    appendcrlf(line); -  debugprint("Complete replay log string to write: '%s', length '%ld'.\n", line, strlen(line)); +  debugprint(DEBUG_FULL, "Complete replay log string to write: '%s', length '%ld'.\n", line, strlen(line));    // Write complete line to file    if ((bytes = fprintf(fp, "%s", line)) < 0) { -    debugprint("error: could not write to replay log file.\n"); +    debugprint(DEBUG_CRIT, "error: could not write to replay log file.\n");      fclose(fp);      return 0;    } @@ -11,6 +11,10 @@  #include "functions.h" +#define DEBUG_CRIT 0 +#define DEBUG_SOME 1 +#define DEBUG_FULL 2 +  #define MAXCHAR 1000  #define TIMELEN 11 // 32-bit unixtime is up to 10 characters (+1 for null char) // TODO - Make this Year 2038 proof  #define TIMELENF 11 // [HH:MM:SS] = 10 characters + 1 for null char @@ -47,7 +47,7 @@ int createserversocket(char *host, char *port) {    }    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s); -  debugprint("bouncer-server: connecting to %s\n", s); +  debugprint(DEBUG_SOME, "bouncer-server: connecting to '%s'\n", s);    freeaddrinfo(servinfo); // all done with this structure @@ -78,7 +78,7 @@ int createclientsocket(char *listenport) {        listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);        if (listener != -1) {          // success, got IPv6! -        debugprint("success, got IPv6!  ai_family: %d\n", p->ai_family); +        debugprint(DEBUG_FULL, "success, got IPv6!  ai_family: '%d'\n", p->ai_family);          break;        }      } @@ -91,7 +91,7 @@ int createclientsocket(char *listenport) {          listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);          if (listener != -1) {            // moderate success, got IPv4! -          debugprint("moderate success, got IPv4!  ai_family: %d\n", p->ai_family); +          debugprint(DEBUG_FULL, "moderate success, got IPv4!  ai_family: '%d'\n", p->ai_family);            break;          }        } @@ -17,6 +17,10 @@  #include "functions.h" +#define DEBUG_CRIT 0 +#define DEBUG_SOME 1 +#define DEBUG_FULL 2 +  #define BACKLOG 10 // maximum length to which the queue of pending connections for sockfd may grow  // get sockaddr, IPv4 or IPv6: | 
