+ }
+ }
+ }
+}
+
+bool userrec::HasPermission(std::string &command)
+{
+ char TypeName[MAXBUF],Classes[MAXBUF],ClassName[MAXBUF],CommandList[MAXBUF];
+ char* mycmd;
+ char* savept;
+ char* savept2;
+
+ // users on u-lined servers can completely bypass
+ // all permissions based checks.
+ //
+ // of course, if this is sent to a remote server and this
+ // server is not ulined there, then that other server
+ // silently drops the command.
+ if (is_uline(this->server))
+ return true;
+
+ // are they even an oper at all?
+ if (*this->oper)
+ {
+ for (int j =0; j < Config->ConfValueEnum("type",&Config->config_f); j++)
+ {
+ Config->ConfValue("type","name",j,TypeName,&Config->config_f);
+ if (!strcmp(TypeName,this->oper))
+ {
+ Config->ConfValue("type","classes",j,Classes,&Config->config_f);
+ char* myclass = strtok_r(Classes," ",&savept);
+ while (myclass)
+ {
+ for (int k =0; k < Config->ConfValueEnum("class",&Config->config_f); k++)
+ {
+ Config->ConfValue("class","name",k,ClassName,&Config->config_f);
+ if (!strcmp(ClassName,myclass))
+ {
+ Config->ConfValue("class","commands",k,CommandList,&Config->config_f);
+ mycmd = strtok_r(CommandList," ",&savept2);
+ while (mycmd)
+ {
+ if ((!strcasecmp(mycmd,command.c_str())) || (*mycmd == '*'))
+ {
+ return true;
+ }
+ mycmd = strtok_r(NULL," ",&savept2);
+ }
+ }
+ }
+ myclass = strtok_r(NULL," ",&savept);
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+bool userrec::AddBuffer(std::string a)
+{
+ std::string b = "";
+ for (unsigned int i = 0; i < a.length(); i++)
+ if ((a[i] != '\r') && (a[i] != '\0') && (a[i] != 7))
+ b = b + a[i];
+ std::stringstream stream(recvq);
+ stream << b;
+ recvq = stream.str();
+ unsigned int i = 0;
+ // count the size of the first line in the buffer.
+ while (i < recvq.length())
+ {
+ if (recvq[i++] == '\n')
+ break;
+ }
+ if (recvq.length() > (unsigned)this->recvqmax)
+ {
+ this->SetWriteError("RecvQ exceeded");
+ WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);
+ }
+ // return false if we've had more than 600 characters WITHOUT
+ // a carriage return (this is BAD, drop the socket)
+ return (i < 600);
+}
+
+bool userrec::BufferIsReady()
+{
+ unsigned int t = recvq.length();
+ for (unsigned int i = 0; i < t; i++)
+ if (recvq[i] == '\n')
+ return true;
+ return false;
+}
+
+void userrec::ClearBuffer()
+{
+ recvq = "";
+}
+
+std::string userrec::GetBuffer()
+{
+ if (recvq == "")
+ return "";
+ char* line = (char*)recvq.c_str();
+ std::string ret = "";
+ while ((*line != '\n') && (*line))
+ {
+ ret = ret + *line;
+ line++;
+ }
+ if ((*line == '\n') || (*line == '\r'))
+ line++;
+ recvq = line;
+ return ret;
+}
+
+void userrec::AddWriteBuf(std::string data)
+{
+ if (this->GetWriteError() != "")
+ return;
+ if (sendq.length() + data.length() > (unsigned)this->sendqmax)
+ {
+ /* Fix by brain - Set the error text BEFORE calling writeopers, because
+ * if we dont it'll recursively call here over and over again trying
+ * to repeatedly add the text to the sendq!
+ */
+ this->SetWriteError("SendQ exceeded");
+ WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax);
+ return;
+ }
+ std::stringstream stream;
+ stream << sendq << data;
+ sendq = stream.str();
+}
+
+// send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
+void userrec::FlushWriteBuf()
+{
+ if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER))
+ {
+ char* tb = (char*)this->sendq.c_str();
+ int n_sent = write(this->fd,tb,this->sendq.length());
+ if (n_sent == -1)
+ {
+ this->SetWriteError(strerror(errno));
+ }
+ else
+ {
+ // advance the queue
+ tb += n_sent;
+ this->sendq = tb;
+ // update the user's stats counters
+ this->bytes_out += n_sent;
+ this->cmds_out++;
+ }
+ }
+}
+
+void userrec::SetWriteError(std::string error)
+{
+ log(DEBUG,"Setting error string for %s to '%s'",this->nick,error.c_str());
+ // don't try to set the error twice, its already set take the first string.
+ if (this->WriteError == "")
+ this->WriteError = error;
+}
+
+std::string userrec::GetWriteError()
+{
+ return this->WriteError;
+}
+
+void AddOper(userrec* user)
+{
+ log(DEBUG,"Oper added to optimization list");
+ all_opers.push_back(user);
+}
+
+void DeleteOper(userrec* user)
+{
+ for (std::vector<userrec*>::iterator a = all_opers.begin(); a < all_opers.end(); a++)
+ {
+ if (*a == user)
+ {
+ log(DEBUG,"Oper removed from optimization list");
+ all_opers.erase(a);
+ return;
+ }
+ }
+}
+
+void kill_link(userrec *user,const char* r)
+{
+ user_hash::iterator iter = clientlist.find(user->nick);
+
+ char reason[MAXBUF];
+
+ strlcpy(reason,r,MAXBUF);
+
+ if (strlen(reason)>MAXQUIT)
+ {
+ reason[MAXQUIT-1] = '\0';
+ }
+
+ log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
+ Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
+ log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
+
+ if (user->registered == 7) {
+ purge_empty_chans(user);
+ FOREACH_MOD(I_OnUserQuit,OnUserQuit(user,reason));
+ WriteCommonExcept(user,"QUIT :%s",reason);
+ }
+
+ user->FlushWriteBuf();
+
+ FOREACH_MOD(I_OnUserDisconnect,OnUserDisconnect(user));
+
+ if (user->fd > -1)
+ {
+ if (Config->GetIOHook(user->port))
+ {
+ try
+ {
+ Config->GetIOHook(user->port)->OnRawSocketClose(user->fd);
+ }
+ catch (ModuleException& modexcept)
+ {
+ log(DEBUG,"Module exception cought: %s",modexcept.GetReason()); \
+ }
+ }
+ ServerInstance->SE->DelFd(user->fd);
+ user->CloseSocket();
+ }
+
+ // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything
+ // if they were an oper with +s.
+ if (user->registered == 7) {
+ // fix by brain: only show local quits because we only show local connects (it just makes SENSE)
+ if (user->fd > -1)
+ WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
+ AddWhoWas(user);
+ }
+
+ if (iter != clientlist.end())
+ {
+ log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
+ if (user->fd > -1)
+ {
+ fd_ref_table[user->fd] = NULL;
+ if (find(local_users.begin(),local_users.end(),user) != local_users.end())
+ {
+ local_users.erase(find(local_users.begin(),local_users.end(),user));
+ log(DEBUG,"Delete local user");
+ }
+ }
+ clientlist.erase(iter);
+ }
+ delete user;
+}
+
+void kill_link_silent(userrec *user,const char* r)
+{
+ user_hash::iterator iter = clientlist.find(user->nick);
+
+ char reason[MAXBUF];
+
+ strlcpy(reason,r,MAXBUF);
+
+ if (strlen(reason)>MAXQUIT)
+ {
+ reason[MAXQUIT-1] = '\0';
+ }
+
+ log(DEBUG,"kill_link: %s '%s'",user->nick,reason);
+ Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
+ log(DEBUG,"closing fd %lu",(unsigned long)user->fd);
+
+ user->FlushWriteBuf();
+
+ if (user->registered == 7) {
+ FOREACH_MOD(I_OnUserQuit,OnUserQuit(user,reason));
+ WriteCommonExcept(user,"QUIT :%s",reason);
+ }
+
+ FOREACH_MOD(I_OnUserDisconnect,OnUserDisconnect(user));
+
+ if (user->fd > -1)
+ {
+ if (Config->GetIOHook(user->port))
+ {
+ try
+ {
+ Config->GetIOHook(user->port)->OnRawSocketClose(user->fd);
+ }
+ catch (ModuleException& modexcept)
+ {
+ log(DEBUG,"Module exception cought: %s",modexcept.GetReason()); \
+ }
+ }
+ ServerInstance->SE->DelFd(user->fd);
+ user->CloseSocket();
+ }
+
+ if (user->registered == 7) {
+ purge_empty_chans(user);
+ }
+
+ if (iter != clientlist.end())
+ {
+ log(DEBUG,"deleting user hash value %lu",(unsigned long)user);
+ if (user->fd > -1)
+ {
+ fd_ref_table[user->fd] = NULL;
+ if (find(local_users.begin(),local_users.end(),user) != local_users.end())
+ {
+ log(DEBUG,"Delete local user");
+ local_users.erase(find(local_users.begin(),local_users.end(),user));
+ }
+ }
+ clientlist.erase(iter);
+ }
+ delete user;
+}
+
+
+/* adds or updates an entry in the whowas list */
+void AddWhoWas(userrec* u)
+{
+ whowas_hash::iterator iter = whowas.find(u->nick);
+ WhoWasUser *a = new WhoWasUser();
+ strlcpy(a->nick,u->nick,NICKMAX-1);
+ strlcpy(a->ident,u->ident,IDENTMAX);
+ strlcpy(a->dhost,u->dhost,160);
+ strlcpy(a->host,u->host,160);
+ strlcpy(a->fullname,u->fullname,MAXGECOS);
+ if (u->server)
+ strlcpy(a->server,u->server,256);
+ a->signon = u->signon;
+
+ /* MAX_WHOWAS: max number of /WHOWAS items
+ * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and
+ * can be replaced by a newer one
+ */
+
+ if (iter == whowas.end())
+ {
+ if (whowas.size() >= (unsigned)WHOWAS_MAX)
+ {
+ for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++)
+ {
+ // 3600 seconds in an hour ;)
+ if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600)))
+ {
+ // delete the old one
+ if (i->second) delete i->second;
+ // replace with new one
+ i->second = a;
+ log(DEBUG,"added WHOWAS entry, purged an old record");
+ return;
+ }
+ }
+ // no space left and user doesnt exist. Don't leave ram in use!
+ log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram");
+ delete a;
+ }
+ else
+ {
+ log(DEBUG,"added fresh WHOWAS entry");
+ whowas[a->nick] = a;