#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #include "TConnection.h" extern list plugins; TConnection::TConnection(string server, string nicklist, char comchar_) { dontreconnect=false; parent=this; newline="\r\n"; comchar=comchar_; sock=-1; buf=new char[BUFLEN]; for (int i=0;i::iterator it=plugins.begin(); it!=plugins.end(); it++) { TPluginParent::hiddenaddplugincontext((*it)->get_default_flags_for_connections(), (*it)->get_context_size()); if (contexts.rbegin()->flags & PFLAGS_EXEC_ONCREATE) (*it)->execute( &(*(contexts.rbegin())) , curr_msg, this, PFLAGS_EXEC_ONCREATE); } } TConnection::~TConnection() { cout << "executing all plugins with the ONDESTROY flag set..." << endl; list::iterator it2=plugins.begin(); ircmessage curr_msg=static_cast(parent)->get_curr_msg(); for (list::iterator it=contexts.begin(); it!=contexts.end(); it++) { if (it->flags & PFLAGS_EXEC_ONDESTROY) (*it2)->execute( &(*it) , curr_msg, this, PFLAGS_EXEC_ONDESTROY); it2++; } delete []buf; } void TConnection::exec_plugins(list plugins) { int reason; list::iterator it2=plugins.begin(); for (list::iterator it=contexts.begin(); it!=contexts.end(); it++) { reason=0; if ((it->flags) & PFLAGS_EXEC_ALWAYS) reason|=PFLAGS_EXEC_ALWAYS; if (((it->flags) & PFLAGS_EXEC_ONEVENT) && (curr_msg) ) reason|=PFLAGS_EXEC_ONEVENT; if (((it->flags) & PFLAGS_EXEC_ONANYEVENT) && (curr_msg) ) reason|=PFLAGS_EXEC_ONANYEVENT; if (reason) (*it2)->execute( &(*it) , curr_msg, this, reason); it2++; } for (list::iterator it=chans.begin();it!=chans.end();it++) (*it)->exec_plugins(plugins); for (list::iterator it=sessions.begin(); it!=sessions.end(); it++) (*it)->exec_plugins(plugins); } void TConnection::addplugincontext(TPlugin* plugin) { TPluginParent::hiddenaddplugincontext(plugin->get_default_flags_for_connections(), plugin->get_context_size()); for (list::iterator it=chans.begin(); it!=chans.end(); it++) (*it)->addplugincontext(plugin); for (list::iterator it=sessions.begin(); it!=sessions.end(); it++) (*it)->addplugincontext(plugin); } void TConnection::removeplugincontext(int x) { TPluginParent::removeplugincontext(x); for (list::iterator it=chans.begin(); it!=chans.end(); it++) (*it)->removeplugincontext(x); for (list::iterator it=sessions.begin(); it!=sessions.end(); it++) (*it)->removeplugincontext(x); } void TConnection::connect(string* server) { sock=socket(AF_INET,SOCK_STREAM,0); if (sock<=0) { sock=-1; throw 1; } hent=gethostbyname(server->c_str()); if (hent) { addr.sin_family=AF_INET; addr.sin_port=htons(6667); addr.sin_addr.s_addr=*((uint32_t*)hent->h_addr_list[0]); if (::connect( sock,(struct sockaddr *)&addr,sizeof(addr))==0) { //cout << "GOOD: we're connected to " << hent->h_name << " (" << inet_ntoa(addr.sin_addr) << ")" << endl; sname=*server; connectname=*server; last_recv=time(NULL); expecting_pong=false; } else { disconnect(); throw 3; //cout << "FATAL: connecting to " << hent->h_name << " (" << inet_ntoa (addr.sin_addr) << ") failed! program ends.\n"; } } else { disconnect(); throw 2; } } void TConnection::disconnect() { if (sock>0) { close(sock); sock=-1; } } string TConnection::getline() { fd_set sockset; struct timeval tv; int retval; int size; char* pos; char* temp; int len; string line=""; if (valid()) //nur empfangen, wenn die verbindung noch steht! { tv.tv_sec=0; tv.tv_usec=10000; //timeout setzen: 10msec warten... FD_ZERO (&sockset); //sockset leeren FD_SET(sock,&sockset); //und füllen retval=select (sock+1,&sockset,NULL,NULL,&tv); if (retval>0) //neue daten da? { last_recv=time(NULL); expecting_pong=false; len=strlen(buf); if ((BUFLEN-1-len)>0) //wenn noch platz im buffer frei ist: { size=recv(sock, buf+len , BUFLEN-1-len , 0); //empfangen ab \0 im puffer (\0 wird überschrieben!) if (size<=0) { cout << "ERROR: connection for '" << sname << "' has been closed!" << endl; disconnect(); } buf[size+len]=0; //aber weiter hinten wieder angehängt! } //aber höchstens so viel wie der buffer packt! } else //nix oder fehler? { if (retval==-1) { cout << "ERROR: error using select ("<=BUFLEN-1) //kein newline, aber trotzdem daten im puffer und puffer voll oO? das kann nur dann sein, wenn der buffer zu klein ist! { cout << "ERROR: buffer isn't empty but there's no NEWLINE!\n discarding the buffer (was: " << buf << ")..." << endl; buf[0]='\0'; } } return line; } void TConnection::register_client(string nicks) { nick=""; send ("USER DrunkenMan foo bar :DrunkenMan by Florian Jung"); nicks+=" "; srandom(time(NULL)); //notfallnick for (int i=0;i<8;i++) nicks+=char( random ()%26 + 'a' ); nicks+=" "; string curr_nick; int pos,oldpos; oldpos=0; pos=nicks.find (' ',0); string answer; ircmessage ans; int numcmd; while (pos!=string::npos) { curr_nick=nicks.substr(oldpos,pos-oldpos); send ("NICK "+curr_nick); while (true) { while ( (!next_message()) && valid() ) usleep (10000); if (valid()==false) //verbindung verloren? throw 99; ans=curr_msg; numcmd=atoi(ans.command.c_str()); if (numcmd==1) //success { nick=curr_nick; sname=ans.origin; //this message always is sent from the server we're on break; } if ((numcmd>=431)&&(numcmd<=439)) //fail { break; } } if (nick!="") break; oldpos=pos+1; pos=nicks.find (' ',oldpos); } if (nick=="") throw 1; } void TConnection::send_raw (string line) { int len; if (valid()) { cout << "SEND: "<::iterator it=sessions.begin(); it!=sessions.end(); it++) //check if this user has already a session if (ucase((*it)->get_name())==ucase(msg.origin_raw)) { newsession=false; break; } if (newsession) //do we have to create a new session for msg.origin_raw? sessions.push_back(new TSession(msg.origin_raw,this)); //create it and push it to the list } if (msg.content[0]==comchar) { if (users.isinlist(msg.origin)) { string info=users.get_info(msg.origin); if (match(msg.content.substr(1),"login")) //bitte um login? { string pass=""; int pos=msg.content.find(' '); if (pos==string::npos) pass=""; else pass=msg.content.substr(pos+1); if (pass==info) //richtiges passwort? { if (!users_li.isinlist(msg.origin)) { users_li.addtolist(msg.origin, msg.origin_raw); cout << "user "<::iterator it=chans.begin(); it!=chans.end(); it++) if (ucase((*it)->get_name())==ucase(msg.params)) { delete *it; chans.erase (it); break; } if (ucase(msg.command)=="KICK") { string where; string victim; where=msg.params.substr(0,msg.params.find(' ',0)); victim=msg.params.substr(msg.params.find(' ',0)+1); if (ucase(victim)==ucase(nick)) for (list::iterator it=chans.begin(); it!=chans.end(); it++) if (ucase(where)==ucase((*it)->get_name())) { delete *it; chans.erase(it); break; } } if (ucase(msg.command)=="NICK") { if (ucase(msg.origin)==ucase(nick)) //we changed our nick? { nick=msg.content; } else //someone else changed his nick? { if (ucase(msg.origin)!=ucase(msg.content)) //check lists only when the nick changed _really_ (not drunkenman to DrunkenMan) { if (isuser(msg.origin_raw)) //was logged in? { send("NOTICE "+msg.content+" :You still were logged in as '"+msg.origin+"'. Logging you out..."); cout << "logging out user '"<::iterator it=chans.begin(); it!=chans.end(); it++) (*it)->interpret_message(msg); for (list::iterator it=sessions.begin(); it!=sessions.end(); it++) (*it)->interpret_message(msg); } void TConnection::logout_all() { cout << "clearing login-entries for " << get_networkname() << "..." << endl; users_li.clear(); masters_li.clear(); } string TConnection::get_nick() { return nick; } string TConnection::get_name() { // return ""; //todo: oder servername? //cout << "connGETNAME" << nick << endl; return sname; } /*TConnection* TConnection::get_parent() { return this; }*/ /*void TConnection::pluginsend(string what) { send(what+NEWLINE); }*/ void TConnection::zerocurrmsg() { curr_msg.origin=""; curr_msg.params=""; curr_msg.content=""; curr_msg.command=""; TPluginParent::zerocurrmsg(); //funktion der elternklasse aufrufen for (list::iterator it=chans.begin(); it!=chans.end(); it++) (*it)->zerocurrmsg(); for (list::iterator it=sessions.begin(); it!=sessions.end(); it++) (*it)->zerocurrmsg(); } void TConnection::loadlists() { users.loadfromfile("./etc/"+get_networkname()+"/users.txt"); masters.loadfromfile("./etc/"+get_networkname()+"/masters.txt"); } void TConnection::savelists() { users.savetofile("./etc/"+get_networkname()+"/users.txt"); masters.savetofile("./etc/"+get_networkname()+"/masters.txt"); } void TConnection::adduser(string nick, string pass) { users.addtolist(nick, pass); } void TConnection::deluser(string nick) { users.removefromlist(nick); } bool TConnection::isuser(string nick) { if (nick.find('!')==string::npos) { cout << "WARNING: called isuser() with stripped nick instead of raw_nick. returning false" << endl; return false; } if ((users_li.isinlist(cut_nick(nick))) && (users_li.get_info(cut_nick(nick))!=nick)) //still logged in, but wrong hostmask? { cout << "removing '"<::iterator it=chans.begin(); it!=chans.end(); it++) if (ucase((*it)->get_name()) == ucase(chan)) return (*it)->get_users(); } bool TConnection::isinchan(string nick,string chan) { return (get_channel_users(chan).isinlist(nick)); } ircmessage TConnection::get_curr_msg() { return curr_msg; } bool TConnection::next_message() { zerocurrmsg(); string temp=getline(); if (temp!="") cout << "@" << sname << ": " << temp << endl; if (!temp.empty()) { interpret_message(parseline(temp)); return true; } else { return false; } } void TConnection::check_session_timeouts() { bool again=false; do { again=false; for (list::iterator it=sessions.begin(); it!=sessions.end(); it++) if (!(*it)->valid()) { delete (*it); //das objekt hinterm iterator löschen sessions.erase(it); //und den pointer aus der liste entfernen again=true; break; } } while (again); } bool TConnection::valid() { return (sock!=-1); } //string TConnection::get_ournick() {return nick;} void TConnection::check_timeout() { if ((time(NULL)>last_recv+60*5) && (!expecting_pong)) //es ist zeit für nen ping { send ("ping "+sname); //ping last_ping=time(NULL); expecting_pong=true; } if ((time(NULL)>last_ping+30) && (expecting_pong)) //wir haben gepingt und keinen pong erhalten? { cout << "ping timeout." << endl; disconnect(); } } string TConnection::get_networkname(string s_name) { int pos; pos=s_name.rfind('.'); if (pos!=string::npos) pos=s_name.rfind('.',pos-1); if (pos!=string::npos) return s_name.substr(pos+1); else return s_name; } string TConnection::get_networkname() { return get_networkname(sname); } string TConnection::get_connectname() { return connectname; } string TConnection::get_channel_topic(string chan) { for (list::iterator it=chans.begin(); it!=chans.end(); it++) if (ucase((*it)->get_name()) == ucase(chan)) return (*it)->get_topic(); } string TConnection::get_channel_modes(string chan) { for (list::iterator it=chans.begin(); it!=chans.end(); it++) if (ucase((*it)->get_name()) == ucase(chan)) return (*it)->get_modes(); } void TConnection::quit(string reason) { send ("QUIT :"+reason); dontreconnect=true; } int TConnection::get_type() {return TYPE_CONN;} void TConnection::communicate(string subject, void *data) { deliver_message(subject, data); for (list::iterator it=chans.begin(); it!=chans.end(); it++) (*it)->deliver_message(subject, data); for (list::iterator it=sessions.begin(); it!=sessions.end(); it++) (*it)->deliver_message(subject, data); } void TConnection::say (string what) //TODO: vlt an alle botmasters senden? { //parent->send("PRIVMSG "+get_name()+" :"+what+NEWLINE); cout << "DEBUG: say doesn't work for TConnection!" << endl; }