/** * \fn void ModuleHandler::SanitizeRuntime() * \brief Deletes all files in the runtime directory. */ void ModuleHandler::SanitizeRuntime() { Log(LOG_DEBUG) << "Cleaning up runtime directory."; Flux::string dirbuf = binary_dir + "/runtime/"; if(!TextFile::IsDirectory(dirbuf)) { #ifndef _WIN32 if(mkdir(dirbuf.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) throw CoreException(printfify("Error making new runtime directory: %s", strerror(errno))); #else if(!CreateDirectory(dirbuf.c_str(), NULL)) throw CoreException(printfify("Error making runtime new directory: %s", strerror(errno))); #endif } else { Flux::vector files = TextFile::DirectoryListing(dirbuf); for(Flux::vector::iterator it = files.begin(); it != files.end(); ++it) Delete(Flux::string(dirbuf + (*it)).c_str()); } }
void Run(CommandSource &source, const Flux::vector ¶ms) { Flux::string chan = params[1]; User *u = source.u; if(!u->IsOwner()) { source.Reply(ACCESS_DENIED); Log(u) << "attempted to make bot part " << chan; return; } if(!IsValidChannel(chan)) source.Reply(CHANNEL_X_INVALID, chan.c_str()); else { Channel *c = findchannel(chan); if(c) c->SendPart(); else source.Reply("I am not in channel \2%s\2", chan.c_str()); Log(u) << "made the bot part " << chan; } }
/** The equivalent of inet_pton * @param type AF_INET or AF_INET6 * @param address The address to place in the sockaddr structures * @param pport An option port to include in the sockaddr structures * @throws A socket exception if given invalid IPs */ void sockaddrs::pton(int type, const Flux::string &address, int pport) { switch (type) { case AF_INET: int i = inet_pton(type, address.c_str(), &sa4.sin_addr); if (i == 0) throw SocketException("Invalid host"); else if (i <= -1) throw SocketException(printfify("Invalid host: %s", strerror(errno))); sa4.sin_family = type; sa4.sin_port = htons(pport); return; case AF_INET6: int i = inet_pton(type, address.c_str(), &sa6.sin6_addr); if (i == 0) throw SocketException("Invalid host"); else if (i <= -1) throw SocketException(printfify("Invalid host: %s", strerror(errno))); sa6.sin6_family = type; sa6.sin6_port = htons(pport); return; default: break; } throw CoreException("Invalid socket type"); }
void OnChannelOp(User *u, Channel *c, const Flux::string &mode, const Flux::string &nick) { if(!u || !c) return; if(c->name != Config->LogChannel) return; CLog("*** %s sets mode %s %s %s", u->nick.c_str(), c->name.c_str(), mode.c_str(), nick.c_str()); }
/** * \fn bool ModuleHandler::DeleteModule(Module *m) * \brief Delete the Module from Module lists and unload it from navn completely * \param Module the Module to be removed */ bool ModuleHandler::DeleteModule(Module *m) { SET_SEGV_LOCATION(); if(!m || !m->handle) return false; void *handle = m->handle; Flux::string filepath = m->filepath; dlerror(); void (*df)(Module *) = function_cast<void ( *)(Module *)>(dlsym(m->handle, "ModunInit")); const char *err = dlerror(); if(!df && err && *err) { Log(LOG_WARN) << "No destroy function found for " << m->name << ", chancing delete..."; delete m; /* we just have to chance they haven't overwrote the delete operator then... */ } else df(m); /* Let the Module delete it self, just in case */ if(handle) if(dlclose(handle)) Log() << "[" << m->name << ".so] " << dlerror(); if(!filepath.empty()) Delete(filepath.c_str()); return true; }
/** * \fn void CheckLogDelete(Log *log) * \brief Check to see if logs need to be removed due to old age * \param log A log class variable */ void CheckLogDelete(Log *log) { Flux::string dir = binary_dir + "/logs/"; if(!TextFile::IsDirectory(dir)) { Log(LOG_TERMINAL) << "Directory " << dir << " does not exist, making new directory."; #ifndef _WIN32 if(mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) throw LogException("Failed to create directory " + dir + ": " + Flux::string(strerror(errno))); #else if(!CreateDirectory(dir.c_str(), NULL)) throw LogException("Failed to create directory " + dir + ": " + Flux::string(strerror(errno))); #endif } Flux::vector files = TextFile::DirectoryListing(dir); if(log) files.push_back(log->filename); if(files.empty()) Log(LOG_TERMINAL) << "No Logs!"; for(Flux::vector::iterator it = files.begin(); it != files.end(); ++it) { Flux::string file = dir + (*it); if(TextFile::IsFile(file)) { Flux::string t = file.isolate('-', ' ').strip('-'); int timestamp = static_cast<int>(t); if(timestamp > (time(NULL) - 86400 * Config->LogAge) && timestamp != starttime) { Delete(file.c_str()); Log(LOG_DEBUG) << "Deleted old logfile " << file; } } } }
void OnPart(User *u, Channel *c, const Flux::string &reason) { if(!u || !c) return; if(c->name != Config->LogChannel) return; CLog("*** %s has parted %s (%s)", u->nick.c_str(), c->name.c_str(), reason.c_str()); }
int uname(struct utsname *info) { // get the system information. OSVERSIONINFOEX wininfo; SYSTEM_INFO si; Flux::string WindowsVer = GetWindowsVersion(); Flux::string cputype; char hostname[256] = "\0"; ZeroMemory(&wininfo, sizeof(OSVERSIONINFOEX)); ZeroMemory(&si, sizeof(SYSTEM_INFO)); wininfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if(!GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&wininfo))) return -1; GetSystemInfo(&si); // Get the hostname if(gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) return -1; if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) cputype = "64-bit"; else if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) cputype = "32-bit"; else if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) cputype = "Itanium 64-bit"; // Fill the utsname struct with the windows system info strcpy(info->sysname, "Windows"); strcpy(info->nodename, hostname); strcpy(info->release, WindowsVer.c_str()); strcpy(info->version, printfify("%ld.%ld-%ld", wininfo.dwMajorVersion, wininfo.dwMinorVersion, wininfo.dwBuildNumber).c_str()); strcpy(info->machine, cputype.c_str()); // Null-Terminate info->nodename[strlen(info->nodename) - 1] = '\0'; info->sysname[strlen(info->sysname) - 1] = '\0'; info->release[strlen(info->sysname) - 1] = '\0'; info->version[strlen(info->version) - 1] = '\0'; info->machine[strlen(info->machine) - 1] = '\0'; }
void Brain(User *u, Flux::string q) { if(!(cdt.requested >= 30)) { cdt.requested++; Log(LOG_TERMINAL) << "Requests: " << cdt.requested; Sanitize(q); Flux::string str = "python brain.py "+q; Flux::string information = execute(str.c_str()); information.trim(); if (information.search_ci("For search options, see Help:Searching")) u->SendMessage(RandomOops()); else if (information.search_ci("may refer to:") || information.search_ci("reasons this message may be displayed:") ) u->SendMessage(RandomAmb()); else u->SendMessage(information.strip()); }else u->SendMessage(TooManyRequests()); }
Flux::string ForwardResolution(const Flux::string &hostname) { struct addrinfo *result, *res; int err = getaddrinfo(hostname.c_str(), NULL, NULL, &result); if(err != 0) { Log(LOG_TERMINAL) << "Failed to resolve " << hostname << ": " << gai_strerror(err); return ""; } bool gothost = false; Flux::string ret = hostname; for(res = result; res != NULL && !gothost; res = res->ai_next) { struct sockaddr *haddr; haddr = res->ai_addr; char address[INET6_ADDRSTRLEN + 1] = "\0"; switch(haddr->sa_family) { case AF_INET: struct sockaddr_in *v4; v4 = reinterpret_cast<struct sockaddr_in*>(haddr); if (!inet_ntop(AF_INET, &v4->sin_addr, address, sizeof(address))) { Log(LOG_DEBUG) << "DNS: " << strerror(errno); return ""; } break; case AF_INET6: struct sockaddr_in6 *v6; v6 = reinterpret_cast<struct sockaddr_in6*>(haddr); if (!inet_ntop(AF_INET6, &v6->sin6_addr, address, sizeof(address))) { Log(LOG_DEBUG) << "DNS: " << strerror(errno); return ""; } break; } ret = address; gothost = true; } freeaddrinfo(result); return ret; }
void Run(CommandSource &source, const Flux::vector ¶ms) { User *u = source.u; Channel *c = source.c; Flux::string area = params[0], tmpfile = TextFile::TempFile(binary_dir+"/runtime/navn_xml.tmp.XXXXXX"); if(tmpfile.empty()) { Log() << "Failed to get temp file"; return; } area.trim(); Flux::string url = Config->Parser->Get("Modules", "WeatherURL", "http://www.google.com/ig/api?weather=%l"); url = url.replace_all_cs("%l", area.is_number_only()?area:area.url_str()); Log(LOG_DEBUG) << "wget weather url \"" << url << "\" for !weather command used"; system(Flux::string("wget -q -O "+tmpfile+" - "+url).c_str()); XMLFile *xf = new XMLFile(tmpfile); Flux::string city = xf->Tags["xml_api_reply"].Tags["weather"].Tags["forecast_information"].Tags["city"].Attributes["data"].Value; Flux::string condition = xf->Tags["xml_api_reply"].Tags["weather"].Tags["current_conditions"].Tags["condition"].Attributes["data"].Value; Flux::string temp_f = xf->Tags["xml_api_reply"].Tags["weather"].Tags["current_conditions"].Tags["temp_f"].Attributes["data"].Value; Flux::string temp_c = xf->Tags["xml_api_reply"].Tags["weather"].Tags["current_conditions"].Tags["temp_c"].Attributes["data"].Value; Flux::string humidity = xf->Tags["xml_api_reply"].Tags["weather"].Tags["current_conditions"].Tags["humidity"].Attributes["data"].Value; Flux::string windy = xf->Tags["xml_api_reply"].Tags["weather"].Tags["current_conditions"].Tags["wind_condition"].Attributes["data"].Value; delete xf; if(city.strip().empty()) { source.Reply("Weather information for \2%s\2 not found.", area.c_str()); return; } int temp_k = static_cast<int>(temp_c) + 273; // Calculate degrees kelvin from degrees celsius c->SendMessage("%s Current Condition: %s, %s, %s, %s %cF %s %cC %iK", city.strip().c_str(), condition.strip().c_str(), humidity.strip().c_str(), windy.strip().c_str(), temp_f.c_str(), 0x00B0, temp_c.c_str(), 0x00B0, temp_k); Log(u, this) << "to get weather for area '" << area << "'"; }
void OnPrivmsgChannel(User *u, Channel *c, const Flux::vector ¶ms) { Flux::string nolog = params.size() == 2 ? params[1] : ""; if(!u || !c) return; if(c->name != Config->LogChannel) return; Flux::string msg = ConcatinateVector(params); if(nolog != "#nl" && u) { if(nolog == "\001ACTION") { msg = msg.erase(0, 8); CLog("*** %s %s", u->nick.c_str(), Flux::Sanitize(msg).c_str()); } else CLog("<%s> %s", u->nick.c_str(), msg.c_str()); } }
void Run(CommandSource &source, const Flux::vector ¶ms) { User *u = source.u; Flux::string chan = params[1]; if(!u->IsOwner()) { source.Reply(ACCESS_DENIED); Log(u) << "attempted to make the bot join " << chan; return; } if(!IsValidChannel(chan)) source.Reply(CHANNEL_X_INVALID, chan.c_str()); else { Log(u) << "made the bot join " << chan; Channel *c = findchannel(chan); if(!c) { ircproto->join(chan); Flux::string WelcomeMessage = Config->WelcomeMessage.replace_all_ci("{botnick}", Config->BotNick); WelcomeMessage.trim(); if(!WelcomeMessage.empty()) ircproto->privmsg(chan, WelcomeMessage); } else { Log(u) << "tried to make bot join " << c->name << " but we're already in that channel"; source.Reply("Already in \2%s\2", c->name.c_str()); } } }
int SocketIO::Send(Socket *s, const Flux::string &buf) { return this->Send(s, buf.c_str(), buf.length()); }
void OnQuit(User *u, const Flux::string &reason) { CLog("*** %s has quit (%s)", u->nick.c_str(), reason.c_str()); }
void SocketIO::Process() { SET_SEGV_LOCATION(); timeval timeout; timeout.tv_sec = Config->SockWait; timeout.tv_usec = 0; //this timeout keeps the bot from being a CPU hog for no reason :) fd_set read = ReadFD, write = WriteFD, except = ExceptFD; FD_ZERO(&read); FD_SET(this->GetFD(), &read); int sres = select(this->GetFD() + 1, &read, &write, &except, &timeout); if(sres == -1 && errno != EINTR) { Log(LOG_DEBUG) << "Select() error: " << strerror(errno); return; } if(throwex) //throw a socket exception if we want to. mainly used for ping timeouts. throw SocketException(throwmsg); bool has_read = FD_ISSET(this->GetFD(), &read); bool has_write = FD_ISSET(this->GetFD(), &write); bool has_error = FD_ISSET(this->GetFD(), &except); if(has_error) { int optval = 0; socklen_t optlen = sizeof(optval); getsockopt(this->GetFD(), SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&optval), &optlen); errno = optval; FOREACH_MOD(I_OnSocketError, OnSocketError(optval ? strerror(errno) : "Unknown socket error")); throw SocketException("Socket error"); } if(has_read) { char tbuf[BUFSIZE + 1] = "\0"; size_t i = recv(this->GetFD(), tbuf, BUFSIZE, 0); if(i <= 0) throw SocketException(printfify("Socket Error: %s", strerror(errno))); sepstream sep(tbuf, '\n'); Flux::string buf; while(sep.GetToken(buf)) { this->LastBuf.clear(); this->LastBuf = buf; if(!this->Read(buf)) throw SocketException("Error reading socket"); } FD_CLR(this->GetFD(), &ReadFD); } if(has_write) { Flux::string buf; while(!this->WriteBuffer.empty()) { buf = this->WriteBuffer.front(); this->WriteBuffer.pop(); int i = ::send(this->GetFD(), buf.c_str(), buf.size(), MSG_NOSIGNAL); if(i <= -1 && !quitting) throw SocketException(printfify("Error writing \"%s\" to socket: %s", buf.c_str(), strerror(errno))); Log(LOG_RAWIO) << "Sent: " << buf << " | " << buf.size() << " bytes"; this->LastBuf.clear(); this->LastBuf = buf; buf.clear(); } FD_CLR(this->GetFD(), &WriteFD); } }
/** * \fn ModErr ModuleHandler::LoadModule(const Flux::string &modname) * \brief Load a Module into the bot * \param Module the Module to load */ ModErr ModuleHandler::LoadModule(const Flux::string &modname) { SET_SEGV_LOCATION(); if(modname.empty()) return MOD_ERR_PARAMS; if(FindModule(modname)) return MOD_ERR_EXISTS; Log() << "Attempting to load Module [" << modname << ']'; Flux::string mdir = binary_dir + "/runtime/" + (modname.search(".so") ? modname + ".XXXXXX" : modname + ".so.XXXXXX"); Flux::string input = Flux::string(binary_dir + "/" + (Config->ModuleDir.empty() ? modname : Config->ModuleDir + "/" + modname) + ".so").replace_all_cs("//", "/"); TextFile mod(input); Flux::string output = TextFile::TempFile(mdir); Log(LOG_RAWIO) << "Runtime Module location: " << output; mod.Copy(output); if(mod.GetLastError() != FILE_IO_OK) { Log(LOG_RAWIO) << "Runtime Copy Error: " << mod.DecodeLastError(); return MOD_ERR_FILE_IO; } dlerror(); // FIXME: Somehow the binary_dir variable is lost when this executes >:| void *handle = dlopen(output.c_str(), RTLD_LAZY | RTLD_LOCAL); const char *err = dlerror(); if(!handle && err && *err) { Log() << '[' << modname << "] " << err; return MOD_ERR_NOLOAD; } dlerror(); Module *(*f)(const Flux::string &) = function_cast<Module * ( *)(const Flux::string &)>(dlsym(handle, "ModInit")); err = dlerror(); if(!f && err && *err) { Log() << "No Module init function, moving on."; dlclose(handle); return MOD_ERR_NOLOAD; } if(!f) throw CoreException("Can't find Module constructor, yet no moderr?"); Module *m; try { m = f(modname); } catch(const ModuleException &e) { Log() << "Error while loading " << modname << ": " << e.GetReason(); return MOD_ERR_EXCEPTION; } m->filepath = output; m->filename = (modname.search(".so") ? modname : modname + ".so"); m->handle = handle; FOREACH_MOD(OnModuleLoad, m); return MOD_ERR_OK; }