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) { 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; }
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; }