From dacd393fefeabafd1306533dd6c5a56e0ab347cc Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Sun, 27 Feb 2011 18:48:35 +0100 Subject: Initial commit --- main.cpp | 515 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 515 insertions(+) create mode 100644 main.cpp (limited to 'main.cpp') diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..a1fb2ba --- /dev/null +++ b/main.cpp @@ -0,0 +1,515 @@ +/* T O D O: + * !votekick und !kick müssen best. kickfunktion aufrufen. die kann dann kickban und nach 3 sec unban oder sowas machen. + * !votekick kann usertest fragen, ob user wahlberechtigt ist. beides per messagebus + * + * ein plugin soll auf verschiedene commands ansprechen (z.B. !kick, !kickban etc) + * + * bei channels, bzw überall: die neue schöne parsemode funktion nutzen =) + * z.B. bei chanmodes: kann man durch parsen der mode-message lösen, dann sparen wir uns das MODE-senden + * + * neuladen von listen + conf via plugins (ermöglicht !useradd etc plugins) + * von listen nicht! nur listenfunktionen wie add/del etc anbieten! + * bot forken lassen (damit nohup wegfallen kann) + * user per nickserv identifizieren. user müssen passwort haben, "" gilt als deaktiviert + * !login ohne params guckt, ob identified, wenn ja, rechte geben + * !login passwort gibt immer rechte + * rechte nehmen bei nick, quit etc, bzw ggf. an den neuen nick weitergeben + * zurückgestellt, da nickserv auf freenode mieft. + * configfile verwenden! (sowohl im bot als auch in plugins!) + * + * + * + * verbinden modularisieren: der bot stellt NUR die verbindung zum server her. der rest (USER, NICK etc) wird über plugins erledigt + * message-system zwischen plugins. + * ansatz1: + * alle plugins haben zeiger auf ein einziges message-bus-objekt + * es kann neue nachrichten aufnehmen und bestehende nachrichten lesen. ggf auch ändern? (todo) + * die nachrichten sehen aus wie folgt: + * betreff, empfänger, daten. betreff ist ein enum, daten ein pointer. empfänger ist entweder ein pointer auf ein TPluginParent, oder NULL für alle. + * wenn eine connection eine nachricht erhält, muss sie diese an alle kinder (channels, sessions) weitergeben. + * plugins (bzw einzelne kontexte) können keine, bestimmte oder alle nachrichten empfangen lassen + * realisiert in DrunkenMan4. nicht wirklich benutzbar! + * !quit für master (=gesamten bot beenden) + * evtl. bannlisten??? (mode #channel +b) + * + * evtl sections in der configfile, oder andere kommentarzeichen ( # ist für channel!) + * oder irgendeine mögl., um #DrunkenMan.autorejoin=false zu setzen + * lösung: # muss am zeilenanfang oder nach einem leerzeichen stehen + * #channelname direkt ist eh sinnlos, muss freenode.net.#DrunkenMan sein. und dann passts ja =) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +using namespace std; + + +#include "myfuncs.h" +#include "TUserList.h" +#include "TPlugin.h" +#include "TSession.h" +#include "TChannel.h" +#include "TConnection.h" +#include "TConfig.h" +#include "main.h" + +list plugins; +TConfig config; +char default_comchar; + + +char comchar_filter(string cc, char fallback); + + + +int main(int argc, char** argv) +{ + config.loadconfig("etc/drunkenman.conf"); //ignore syntax errors + + int conf_UID; + if (!config.is_integer("UID")) + { + cout << "looking up UID for user '"<pw_uid; + } + else + { + cout << "FATAL: failed to look up UID!"<gr_gid; + } + else + { + cout << "FATAL: failed to look up GID!"<pw_name:"unknown") << "("<gr_name : "unknown") << "("<::iterator it; + for (it=plugins.begin(); it!=plugins.end(); it++) //schauen, ob es schon geladen ist... + { + if (*it) //kein NULLpointer (sollte auch keiner sein, nur zur sicherheit...) + { + if (lcase((*it)->get_name())==lcase(what)) //schon geladen oO? + { + fail=true; + break; + } + } + } + if (fail) // schon geladen! + { + cout << "ERROR: plugin '" << what << "' is already loaded!" << endl; + } + else // noch nicht geladen; wir können weitermachen // L O A D P L U G I N + { + TPlugin* tempptr; + try //versuche, das plugin zu laden + { + tempptr=new TPlugin(what); + plugins.push_back(tempptr); //ab hier hatten wir erfolg! + cout << "plugin '"< connections; + + + string conf_servers=config.get_string("connect"); + if (trim(conf_servers)=="") + { + cout << "no servers specified. exiting..." << endl; + exit(1); + } + string temp_conf_servers=conf_servers; + string temp_server, temp_net; + while ((temp_server=split(temp_conf_servers))!="") + { + cout << "connecting to " << temp_server << "..." << endl; + temp_net=TConnection::get_networkname(temp_server); + try + { + TConnection* temp=new TConnection(temp_server,config.get_valid_string(temp_net+".nick", "DrunkenMan")+" "+config.get_valid_string(temp_net+".altnicks", "DrunkenMan3 Drunken_Man"),comchar_filter(config.get_string(temp_net+".comchar"), default_comchar)); + connections.push_back (temp); + } + catch (...) + { + cout << "unable to connect to "<< temp_server <<"!" << endl; + } + } + + ircmessage msg; + + list::iterator conn_it; + TConnection* curr_conn; + int cnt; + + while (true) + { + cnt=0; + for (conn_it=connections.begin(); conn_it!=connections.end(); conn_it++) + { + cnt++; + curr_conn=*conn_it; + if (curr_conn->next_message()) + { + msg=curr_conn->get_curr_msg(); + + if (ucase(msg.command)=="PRIVMSG") + { + if (msg.content[0]==curr_conn->comchar) + { + string cmd=msg.content.substr(1); + if (match(cmd, "reload_config")) + { + if (curr_conn->ismaster(msg.origin_raw)) + { + try + { + config.loadconfig("etc/drunkenman.conf"); + curr_conn->send("notice "+msg.origin+" :configuration reloaded."); + + default_comchar=comchar_filter(config.get_string("comchar"),'!'); + + for (list::iterator conn_it2=connections.begin(); conn_it2!=connections.end(); conn_it2++) + (*conn_it2)->comchar=comchar_filter(config.get_string((*conn_it2)->get_networkname()+".comchar"), default_comchar); + } + catch (...) + { + curr_conn->send("notice "+msg.origin+" :reloading configuration failed!"); + } + } + else // !ismaster + { + curr_conn->send("notice "+msg.origin+" :sorry, but you aren't a master!"); + } + } + + if (match(cmd, "reload_lists")) + { + if (curr_conn->ismaster(msg.origin_raw)) + { + string temp_succ(""), temp_fail(""); + for (list::iterator conn_it2=connections.begin(); conn_it2!=connections.end(); conn_it2++) + { + try + { + (*conn_it2)->loadlists(); + temp_succ=temp_succ+", "+(*conn_it2)->get_networkname(); + } + catch (...) + { + temp_fail=temp_succ+", "+(*conn_it2)->get_networkname(); + } + } + if (temp_succ!="") + curr_conn->send("notice "+msg.origin+" :successfully reloaded lists for "+temp_succ.substr(2)); + if (temp_fail!="") + curr_conn->send("notice "+msg.origin+" :reloading lists failed for "+temp_fail.substr(2)); + } + else // !ismaster + { + curr_conn->send("notice "+msg.origin+" :sorry, but you aren't a master!"); + } + } + + if (match(cmd, "clear_logins")) + { + if (curr_conn->ismaster(msg.origin_raw)) + { + string temp_succ(""), temp_fail(""); + for (list::iterator conn_it2=connections.begin(); conn_it2!=connections.end(); conn_it2++) + (*conn_it2)->logout_all(); + + curr_conn->send("notice "+msg.origin+" :successfully cleared all login entries. note that also you have to re-login!"); + } + else // !ismaster + { + curr_conn->send("notice "+msg.origin+" :sorry, but you aren't a master!"); + } + } + + if (match(cmd,"connect")) + { + if (curr_conn->ismaster(msg.origin_raw)) + { + //string server=msg.content.substr(9); + string server=ntharg(cmd,2); + curr_conn->send("notice "+msg.origin+" :trying to connect to "+server+"..."); + curr_conn->send("notice "+msg.origin+" :this may take a while. while connecting, the bot won't respond."); + + try + { + string temp_net=TConnection::get_networkname(server); + TConnection* temp=new TConnection(server,config.get_valid_string(temp_net+".nick","DrunkenMan")+" "+config.get_valid_string(temp_net+".altnicks","DrunkenMan3 Drunken_Man"),comchar_filter(config.get_string(temp_net+".comchar"), default_comchar)); + connections.push_back (temp); + curr_conn->send("notice "+msg.origin+" :connection to "+server+" was established successfully."); + + } + catch (...) + { + curr_conn->send("notice "+msg.origin+" :connecting to "+server+" failed!"); + } + + } + else // !ismaster + { + curr_conn->send("notice "+msg.origin+" :sorry, but you aren't a master!"); + } + } + + if (match(cmd,"load")) + { + if (curr_conn->ismaster(msg.origin_raw)) + { + //string what=msg.content.substr(6); + string what=ntharg(cmd,2); + cout << "trying to load plugin '" << what << "'..." << endl; + bool fail=false; + + list::iterator it; + for (it=plugins.begin(); it!=plugins.end(); it++) //schauen, ob es schon geladen ist... + { + if (*it) //kein NULLpointer (sollte auch keiner sein, nur zur sicherheit...) + { + if (lcase((*it)->get_name())==lcase(what)) //schon geladen oO? + { + fail=true; + break; + } + } + } + if (fail) // schon geladen! + { + cout << "ERROR: plugin '" << what << "' is already loaded!" << endl; + curr_conn->send("notice "+msg.origin+" :plugin '"+what+"' is already loaded!"); + } + else // noch nicht geladen; wir können weitermachen // L O A D P L U G I N + { + TPlugin* tempptr; + try //versuche, das plugin zu laden + { + tempptr=new TPlugin(what); + plugins.push_back(tempptr); //ab hier hatten wir erfolg! + cout << "plugin '"<send("notice "+msg.origin+" :plugin '"+what+"' has been loaded successfully."); + + curr_conn->addplugincontext(tempptr); + + //alle connections davon informieren, damit diese ihre contexts anpassen können + //diese müssen auch alle ihrer channels informieren (selber zwecke) + } + catch (...) //fehlgeschlagen? + { + cout << "ERROR: could not load plugin '" << what << "'!" << endl; + curr_conn->send("notice "+msg.origin+" :could not load plugin '"+what+"'!"); + curr_conn->send("notice "+msg.origin+" :see log for details"); + } // done. + } + } + else // !ismaster + { + curr_conn->send("notice "+msg.origin+" :sorry, but you aren't a master!"); + } + } + if (match(cmd,"unload")) + { + if (curr_conn->ismaster(msg.origin_raw)) + { + //string what=msg.content.substr(8); + string what=ntharg(cmd,2); + cout << "..." << endl; + bool fail=true; + //ggf. entladen + list::iterator it; + for (it=plugins.begin(); it!=plugins.end(); it++) //schauen, ob es schon geladen ist... + { + if (*it) //kein NULLpointer (sollte auch keiner sein, nur zur sicherheit...) + { + if (lcase((*it)->get_name())==lcase(what)) //schon geladen? + { + fail=false; + break; + } + } + } + + if (fail) //nicht geladen! + { + cout << "ERROR: plugin '" << what << "' is not loaded!" << endl; + curr_conn->send("notice "+msg.origin+" :plugin '"+what+"' is not loaded!"); + } + else //geladen :)? // U N L O A D P L U G I N + { + cout << "removing plugincontext..." <removeplugincontext( distance(plugins.begin(),it) ); + delete *it; + plugins.erase(it); + curr_conn->send("notice "+msg.origin+" :plugin '"+what+"' has been unloaded successfully."); + } // done. + } + else // !ismaster + { + curr_conn->send("notice "+msg.origin+" :sorry, but you aren't a master!"); + } + } + } + } + } + + curr_conn->check_timeout(); + if (!curr_conn->valid()) + { + string temp=curr_conn->get_connectname(); + string temp_net=curr_conn->get_networkname(); + int nfails=0; + bool retry=!(curr_conn->dontreconnect); + cout << "ERROR: connection for '" << temp << "' has been closed!" << endl; + delete curr_conn; + curr_conn=0; + + if (retry) + while (curr_conn==0) + { + cout << "trying to connect to '" << temp << "'... " << endl; + try + { + curr_conn=new TConnection(temp, config.get_valid_string(temp_net+".nick", "DrunkenMan")+" "+config.get_valid_string(temp_net+".altnicks","DrunkenMan3 Drunken_Man"),comchar_filter(config.get_string(temp_net+".comchar"), default_comchar)); + cout << "success!" << endl; + break; + } + catch(...) + { + cout << "failed." << endl; + curr_conn=0; + nfails++; + } + if (nfails>=3) break; + usleep (5000000); + } + + if (curr_conn==0) + { + if (retry) + cout << "[ERROR] unable to reconnect to '" << temp << "'!" << endl; + else + cout << "connection '" << temp << "' has been closed successfully." << endl; + + connections.erase(conn_it); + break; + } + else + { + *conn_it=curr_conn; + } + } + curr_conn->check_session_timeouts(); + curr_conn->exec_plugins(plugins); + } + + if (cnt==0) + { + cout << "last connection has been closed :(" << endl; + cout << "program will exit now." << endl << endl; + exit (1); + } + } +} + + +char comchar_filter(string cc, char fallback) +{ + if (cc.length()!=1) + return fallback; + else + return cc[0]; +} -- cgit v1.2.1