bool Log_WriteMsg(const char *InStream, MessageType MType) { char OutBuf[2048], Origin[2048], Message[2048]; char Nick[128], Ident[128], Mask[128], *Worker = Origin; if (MType == IMSG_TOPIC) return Log_TopicLog(InStream); else if (MType == IMSG_MODE) return Log_ModeLog(InStream); if (!IRC_BreakdownNick(InStream, Nick, Ident, Mask) || !*Nick || !*Ident || !*Mask) return true; IRC_GetMessageData(InStream, Origin); if (MType != IMSG_JOIN && MType != IMSG_QUIT && MType != IMSG_NICK && MType != IMSG_PART) { Worker = strchr(Worker, ' '); *Worker++ = '\0'; while (*Worker == ' ' ) ++Worker; if (*Worker == ':') ++Worker; strncpy(Message, Worker, sizeof Message - 1); Message[sizeof Message - 1] = '\0'; } if (MType == IMSG_PART || MType == IMSG_JOIN) /*I really doubt I'll ever see that on a JOIN.*/ { if ((Worker = strstr(Origin, " :"))) *Worker = '\0'; } else if (MType == IMSG_KICK) { if ((Worker = strstr(Message, " :"))) *Worker = '\0'; } switch (MType) { case IMSG_PRIVMSG: if (!strncmp(Message, "\01ACTION", strlen("\01ACTION"))) { char *Temp = strchr(Message + 1, '\01'); if (Temp) *Temp = '\0'; snprintf(OutBuf, sizeof OutBuf, "(%s) **%s %s**", *Origin == '#' ? Origin : Nick, Nick, Message + strlen("\01ACTION ")); } else snprintf(OutBuf, sizeof OutBuf, "(%s) <%s>: %s", *Origin == '#' ? Origin : Nick, Nick, Message); break; case IMSG_NOTICE: snprintf(OutBuf, sizeof OutBuf, "(%s) <%s> (notice): %s", *Origin == '#' ? Origin : Nick, Nick, Message); break; case IMSG_JOIN: snprintf(OutBuf, sizeof OutBuf, "<%s!%s@%s joined %s>", Nick, Ident, Mask, Origin); break; case IMSG_PART: snprintf(OutBuf, sizeof OutBuf, "<%s!%s@%s left %s>", Nick, Ident, Mask, Origin); break; case IMSG_KICK: snprintf(OutBuf, sizeof OutBuf, "<%s was kicked from %s by %s>", Message, Origin, Nick); break; case IMSG_NICK: case IMSG_QUIT: { struct ChannelTree *Worker = Channels; if (MType == IMSG_QUIT) { snprintf(OutBuf, sizeof OutBuf, "<%s!%s@%s has quit: %s>", Nick, Ident, Mask, *Origin == ':' ? Origin + 1 : Origin); } else { snprintf(OutBuf, sizeof OutBuf, "<%s is now known as %s>", Nick, Origin); } if (!Channels) { Log_CoreWrite(OutBuf, Nick); return true; } for (; Worker; Worker = Worker->Next) { if (IRC_UserInChannelP(Worker, Nick)) { Log_CoreWrite(OutBuf, Worker->Channel); NoLogToConsole = true; } } NoLogToConsole = false; return true; } default: return false; } Log_CoreWrite(OutBuf, *Origin == '#' ? Origin : Nick); return true; }
static bool Main_GenConfig(void) { FILE *Descriptor = NULL; char LineBuf[4096], CurChan[128], *Worker = LineBuf; char FileBuf[16384] = { '\0' }; /*16K max config size for generator. Should be ridiculously more than enough.*/ register unsigned Inc = 0; char Nick[128], Ident[128], Mask[128]; char OutBuf[sizeof LineBuf + 128], OutPath[256]; struct stat FileStat; puts("Generating a config file as per your request.\n" "I'll need some information from you now.\n"); printf("What is the hostname of the IRC server? e.g. irc.myserver.net\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; snprintf(OutBuf, sizeof OutBuf, "Hostname=%s\n", LineBuf); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); printf("What is the port number of the IRC server?\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; snprintf(OutBuf, sizeof OutBuf, "PortNum=%s\n", LineBuf); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); printf("What nickname do you want to give the bot?\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; snprintf(OutBuf, sizeof OutBuf, "Nick=%s\n", LineBuf); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); printf("What ident do you want to give the bot?\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; snprintf(OutBuf, sizeof OutBuf, "Ident=%s\n", LineBuf); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); printf("What do you want the 'real name' of the bot to be?\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; snprintf(OutBuf, sizeof OutBuf, "RealName=%s\n", LineBuf); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); printf("Please enter a list of channels separated by spaces.\n" "Put a comma followed by a prefix to specify a command prefix for that channel.\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; if (*LineBuf) { do { for (Inc = 0; Worker[Inc] != ' ' && Worker[Inc] != '\0' && Inc < sizeof CurChan - 1; ++Inc) { CurChan[Inc] = Worker[Inc]; } CurChan[Inc] = '\0'; snprintf(OutBuf, sizeof OutBuf, "Channel=%s\n", CurChan); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); printf("Added channel %s\n", CurChan); } while ((Worker = SubStrings.Line.WhitespaceJump(Worker))); } LLogging: printf("Do you want to enable logging? Please enter y or n.\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; switch (tolower(*LineBuf)) { case 'y': snprintf(OutBuf, sizeof OutBuf, "Logging=true\n"); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); LLogPMs: printf("Do you want to log private messages sent to the bot? Please enter y or n.\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; switch (tolower(*LineBuf)) { case 'y': snprintf(OutBuf, sizeof OutBuf, "LogPMs=true\n"); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); break; case 'n': snprintf(OutBuf, sizeof OutBuf, "LogPMs=false\n"); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); break; default: putchar('\n'); goto LLogPMs; break; } break; case 'n': snprintf(OutBuf, sizeof OutBuf, "Logging=false\n"); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); break; default: goto LLogging; break; } OwnerGet: printf("Enter a user's vhost to be bot 'owner', which is of the format 'nick!ident@ip_or_hostmask'.\n" "Wildcard '*' is accepted if it denotes an entire field as wild.\n--> "); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; if (!IRC_BreakdownNick(LineBuf, Nick, Ident, Mask)) { puts("That's not a valid vhost. Try again."); goto OwnerGet; } snprintf(OutBuf, sizeof OutBuf, "BotOwner=%s!%s@%s\n", Nick, Ident, Mask); SubStrings.Cat(FileBuf, OutBuf, sizeof FileBuf); printf("A config file has been generated, but now we need a place to save it.\n" "Enter a filename for the new config file. aqu4bot.conf is what it should be\n" "named if you intend to use this config file.\n--> "); fgets(OutPath, sizeof OutPath, stdin); OutPath[strlen(OutPath) - 1] = '\0'; if (stat(OutPath, &FileStat) == 0) { Bot_SetTextColor(YELLOW); printf("WARNING: "); Bot_SetTextColor(ENDCOLOR); printf("The config file \"%s\" already exists! Overwrite it?\n" "Please enter y or n\n--> ", OutPath); fgets(LineBuf, sizeof LineBuf, stdin); LineBuf[strlen(LineBuf) - 1] = '\0'; if (tolower(*LineBuf) != 'y') { puts("Aborting, not overwriting the config file."); return false; } } Bot_SetTextColor(YELLOW); printf("Writing config file to \"%s\"...\n", OutPath); Bot_SetTextColor(ENDCOLOR); if (!(Descriptor = fopen(OutPath, "w"))) { Bot_SetTextColor(RED); puts("\nFailed to save config file!"); Bot_SetTextColor(ENDCOLOR); puts("Make sure it's a valid location,\nand that you have permission to write there."); return false; } /*Add a bit of help at the top of the file.*/ fprintf(Descriptor, "#aqu4bot config file generated with --genconfig option.\n\n" "#Other options include:\n" "#NickservPwd=Nickserv Password\n" "#Prefix=$ (The global command prefix)\n" "#SendDelay=8 (tenths of a second to wait between sending messages)\n" "#SetBotmode=true/false (some networks request you set a special mode for your IRC bots.)\n" "#Admin=nick!ident@mask (Add a less privileged admin who can administrate channels etc,\n" "#but not administrate the bot itself.)\n" "#NoControlCodes=true/false (some networks will not allow you bold/etc.\n"); fwrite(FileBuf, 1, strlen(FileBuf), Descriptor); fflush(NULL); fclose(Descriptor); Bot_SetTextColor(GREEN); puts("Done!"); Bot_SetTextColor(ENDCOLOR); return true; }
void IRC_Loop(void) { /*Most of the action is triggered here.*/ char MessageBuf[2048]; while (1) { if (!Net_Read(SocketDescriptor, MessageBuf, sizeof MessageBuf, true)) { /*No command should ever call Net_Read() besides us and the connecting stuff that comes before us.*/ puts("\033[31mCONNECTION LOST\033[0m"); close(SocketDescriptor); exit(1); } if (!strncmp(MessageBuf, "PING ", strlen("PING "))) IRC_Pong(MessageBuf); /*Respond to pings.*/ switch (IRC_GetMessageType(MessageBuf)) { char Nick[1024], Ident[1024], Mask[1024]; case IMSG_PRIVMSG: { char MessageData[2048], *TC = NULL, Channel[1024]; unsigned long Inc = 0; if (!IRC_BreakdownNick(MessageBuf, Nick, Ident, Mask)) continue; IRC_GetMessageData(MessageBuf, MessageData); if (Auth_IsBlacklisted(Nick, Ident, Mask)) continue; /*Says "you are not going to be listened to bud.*/ if (strcmp(Nick, ServerInfo.Nick) != 0) Log_WriteMsg(MessageBuf, IMSG_PRIVMSG); for (; MessageData[Inc] != ' ' && MessageData[Inc] && Inc < sizeof Channel - 1; ++Inc) { Channel[Inc] = MessageData[Inc]; } Channel[Inc] = '\0'; TC = strchr(MessageData, ' ') + 1; if (*TC == ':') ++TC; if (*TC == 0x01) { /*IRC escape code thingy...*/ if (!strcmp(TC, "\01VERSION\01")) { IRC_Notice(Nick, "\01VERSION aqu4bot " BOT_VERSION "\01"); } else if (!strncmp(TC, "\01PING", strlen("\01PING"))) { IRC_Notice(Nick, TC); } } else { /*I don't feel like including time.h*/ time_t time(time_t*); CMD_ProcessCommand(MessageBuf); if (strcmp(Nick, ServerInfo.Nick) != 0) { CMD_UpdateSeenDB(time(NULL), Nick, Channel, TC); } } break; } case IMSG_NOTICE: if (!IRC_BreakdownNick(MessageBuf, Nick, Ident, Mask)) continue; if (Auth_IsBlacklisted(Nick, Ident, Mask)) continue; if (strcmp(Nick, ServerInfo.Nick) != 0) Log_WriteMsg(MessageBuf, IMSG_NOTICE); break; case IMSG_INVITE: { if (!IRC_BreakdownNick(MessageBuf, Nick, Ident, Mask)) continue; if (Auth_IsBlacklisted(Nick, Ident, Mask)) continue; if (Auth_IsAdmin(Nick, Ident, Mask, NULL)) { const char *TWorker = MessageBuf; TWorker = strchr(TWorker, '#'); if (!TWorker) { IRC_Message(Nick, "There is something wrong, and although you are an admin," "your invite request is either malformed or it's my fault."); break; } IRC_Message(Nick, "Coming."); if (IRC_JoinChannel(TWorker)) IRC_AddChannelToTree(TWorker); } else { IRC_Message(Nick, "I'm sorry, I can only accept invite requests from my admins."); } break; } case IMSG_KICK: { char InBuf[2048], *Worker = InBuf; IRC_GetMessageData(MessageBuf, InBuf); Log_WriteMsg(MessageBuf, IMSG_KICK); if (!(Worker = strchr(InBuf, ' '))) break; *Worker = '\0'; IRC_DelChannelFromTree(*InBuf == ':' ? InBuf + 1 : InBuf); break; } case IMSG_QUIT: { if (!IRC_BreakdownNick(MessageBuf, Nick, Ident, Mask)) continue; if (!strcmp(Nick, ServerInfo.Nick)) { IRC_Quit(NULL); IRC_ShutdownChannelTree(); Auth_ShutdownAdmin(); CMD_SaveSeenDB(); Auth_ShutdownBlacklist(); exit(0); } break; } case IMSG_JOIN: { if (!IRC_BreakdownNick(MessageBuf, Nick, Ident, Mask)) continue; Log_WriteMsg(MessageBuf, IMSG_JOIN); while (CMD_ReadTellDB(Nick)); break; } case IMSG_PART: if (!IRC_BreakdownNick(MessageBuf, Nick, Ident, Mask)) continue; Log_WriteMsg(MessageBuf, IMSG_PART); break; case IMSG_NICK: { char NewNick[1024]; IRC_GetMessageData(MessageBuf, NewNick); while (CMD_ReadTellDB(*NewNick == ':' ? NewNick + 1 : NewNick)); } default: break; } } }
Bool Log_WriteMsg(const char *InStream, MessageType MType) { FILE *Descriptor = NULL; char Filename[1024], OutBuf[2048], Origin[2048], Message[2048]; char Nick[1024], Ident[1024], Mask[1024], *Worker = Origin; time_t Time = time(NULL); struct tm TimeStruct; char TimeString[1024]; struct stat DirStat; if (!Logging) return true; if (!IRC_BreakdownNick(InStream, Nick, Ident, Mask) || !*Nick || !*Ident || !*Mask) return true; IRC_GetMessageData(InStream, Origin); if (*Origin != '#' && !LogPMs) return true; if (MType != IMSG_JOIN && MType != IMSG_PART) { Worker = strchr(Worker, ' '); *Worker++ = '\0'; while (*Worker == ' ' ) ++Worker; if (*Worker == ':') ++Worker; strncpy(Message, Worker, sizeof Message - 1); Message[sizeof Message - 1] = '\0'; } if (MType == IMSG_PART || MType == IMSG_JOIN) /*I really doubt I'll ever see that on a JOIN.*/ { if ((Worker = strstr(Origin, " :"))) *Worker = '\0'; } else if (MType == IMSG_KICK) { if ((Worker = strstr(Message, " :"))) *Worker = '\0'; } if (stat("logs", &DirStat) != 0) { if (mkdir("logs", 0755) != 0) return false; } snprintf(Filename, sizeof Filename, "logs/%s.txt", *Origin == '#' ? Origin : Nick); gmtime_r(&Time, &TimeStruct); strftime(TimeString, sizeof TimeString, "[%Y-%m-%d %H:%M:%S UTC]", &TimeStruct); switch (MType) { case IMSG_PRIVMSG: if (!strncmp(Message, "\01ACTION", strlen("\01ACTION"))) { char *Temp = strchr(Message + 1, '\01'); if (Temp) *Temp = '\0'; snprintf(OutBuf, sizeof OutBuf, "%s **%s %s**\n", TimeString, Nick, Message + strlen("\01ACTION ")); } else snprintf(OutBuf, sizeof OutBuf, "%s %s: %s\n", TimeString, Nick, Message); break; case IMSG_NOTICE: snprintf(OutBuf, sizeof OutBuf, "%s %s (notice): %s\n", TimeString, Nick, Message); break; case IMSG_JOIN: snprintf(OutBuf, sizeof OutBuf, "%s <%s joined %s>\n", TimeString, Nick, Origin); break; case IMSG_PART: snprintf(OutBuf, sizeof OutBuf, "%s <%s left %s>\n", TimeString, Nick, Origin); break; case IMSG_KICK: snprintf(OutBuf, sizeof OutBuf, "%s <%s was kicked from %s by %s>\n", TimeString, Message, Origin, Nick); break; default: return false; } if (!(Descriptor = fopen(Filename, "a"))) { return false; } fwrite(OutBuf, 1, strlen(OutBuf), Descriptor); fclose(Descriptor); return true; }