From 71bedf497cde8b0b38afbb366828b3df9c2803d6 Mon Sep 17 00:00:00 2001 From: brain Date: Mon, 19 Dec 2005 18:04:22 +0000 Subject: git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@2578 e03df62e-2008-0410-955e-edbf42e46eb7 --- docs/module-doc/users_8cpp-source.html | 1037 +++++++++++++++++++++++--------- 1 file changed, 769 insertions(+), 268 deletions(-) (limited to 'docs/module-doc/users_8cpp-source.html') diff --git a/docs/module-doc/users_8cpp-source.html b/docs/module-doc/users_8cpp-source.html index 5cc9b05f2..d43be846f 100644 --- a/docs/module-doc/users_8cpp-source.html +++ b/docs/module-doc/users_8cpp-source.html @@ -38,279 +38,780 @@ 00029 #include "inspstring.h" 00030 #include "commands.h" 00031 #include "helperfuncs.h" -00032 -00033 extern ServerConfig* Config; -00034 extern time_t TIME; -00035 -00036 userrec::userrec() -00037 { -00038 // the PROPER way to do it, AVOID bzero at *ALL* costs -00039 strcpy(nick,""); -00040 strcpy(ip,"127.0.0.1"); -00041 timeout = 0; -00042 strcpy(ident,""); -00043 strcpy(host,""); -00044 strcpy(dhost,""); -00045 strcpy(fullname,""); -00046 strcpy(modes,""); -00047 server = (char*)FindServerNamePtr(Config->ServerName); -00048 strcpy(awaymsg,""); -00049 strcpy(oper,""); -00050 reset_due = TIME; -00051 lines_in = 0; -00052 fd = lastping = signon = idle_lastmsg = nping = registered = 0; -00053 flood = port = bytes_in = bytes_out = cmds_in = cmds_out = 0; -00054 haspassed = false; -00055 dns_done = false; -00056 recvq = ""; -00057 sendq = ""; -00058 chans.clear(); -00059 invites.clear(); -00060 } -00061 -00062 userrec::~userrec() -00063 { -00064 } -00065 -00066 void userrec::CloseSocket() -00067 { -00068 shutdown(this->fd,2); -00069 close(this->fd); -00070 } -00071 -00072 char* userrec::GetFullHost() -00073 { -00074 static char result[MAXBUF]; -00075 snprintf(result,MAXBUF,"%s!%s@%s",nick,ident,dhost); -00076 return result; -00077 } -00078 -00079 int userrec::ReadData(void* buffer, size_t size) -00080 { -00081 if (this->fd > -1) -00082 { -00083 return read(this->fd, buffer, size); -00084 } -00085 else return 0; -00086 } -00087 +00032 #include "typedefs.h" +00033 #include "socketengine.h" +00034 #include "hashcomp.h" +00035 #include "message.h" +00036 #include "wildcard.h" +00037 #include "xline.h" +00038 +00039 extern InspIRCd* ServerInstance; +00040 extern int WHOWAS_STALE; +00041 extern int WHOWAS_MAX; +00042 extern std::vector<Module*> modules; +00043 extern std::vector<ircd_module*> factory; +00044 extern std::vector<InspSocket*> module_sockets; +00045 extern int MODCOUNT; +00046 extern InspSocket* socket_ref[65535]; +00047 extern time_t TIME; +00048 extern userrec* fd_ref_table[65536]; +00049 extern ServerConfig *Config; +00050 extern user_hash clientlist; +00051 extern whowas_hash whowas; +00052 std::vector<userrec*> local_users; +00053 +00054 std::vector<userrec*> all_opers; +00055 +00056 template<typename T> inline string ConvToStr(const T &in) +00057 { +00058 stringstream tmp; +00059 if (!(tmp << in)) return string(); +00060 return tmp.str(); +00061 } +00062 +00063 userrec::userrec() +00064 { +00065 // the PROPER way to do it, AVOID bzero at *ALL* costs +00066 strcpy(nick,""); +00067 strcpy(ip,"127.0.0.1"); +00068 timeout = 0; +00069 strcpy(ident,""); +00070 strcpy(host,""); +00071 strcpy(dhost,""); +00072 strcpy(fullname,""); +00073 strcpy(modes,""); +00074 server = (char*)FindServerNamePtr(Config->ServerName); +00075 strcpy(awaymsg,""); +00076 strcpy(oper,""); +00077 reset_due = TIME; +00078 lines_in = 0; +00079 fd = lastping = signon = idle_lastmsg = nping = registered = 0; +00080 flood = port = bytes_in = bytes_out = cmds_in = cmds_out = 0; +00081 haspassed = false; +00082 dns_done = false; +00083 recvq = ""; +00084 sendq = ""; +00085 chans.clear(); +00086 invites.clear(); +00087 } 00088 -00089 char* userrec::GetFullRealHost() +00089 userrec::~userrec() 00090 { -00091 static char fresult[MAXBUF]; -00092 snprintf(fresult,MAXBUF,"%s!%s@%s",nick,ident,host); -00093 return fresult; -00094 } -00095 -00096 bool userrec::IsInvited(char* channel) -00097 { -00098 for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) -00099 { -00100 if (i->channel) { -00101 if (!strcasecmp(i->channel,channel)) -00102 { -00103 return true; -00104 } -00105 } -00106 } -00107 return false; -00108 } -00109 -00110 InvitedList* userrec::GetInviteList() -00111 { -00112 return &invites; +00091 } +00092 +00093 void userrec::CloseSocket() +00094 { +00095 shutdown(this->fd,2); +00096 close(this->fd); +00097 } +00098 +00099 char* userrec::GetFullHost() +00100 { +00101 static char result[MAXBUF]; +00102 snprintf(result,MAXBUF,"%s!%s@%s",nick,ident,dhost); +00103 return result; +00104 } +00105 +00106 int userrec::ReadData(void* buffer, size_t size) +00107 { +00108 if (this->fd > -1) +00109 { +00110 return read(this->fd, buffer, size); +00111 } +00112 else return 0; 00113 } 00114 -00115 void userrec::InviteTo(char* channel) -00116 { -00117 Invited i; -00118 strlcpy(i.channel,channel,CHANMAX); -00119 invites.push_back(i); -00120 } -00121 -00122 void userrec::RemoveInvite(char* channel) -00123 { -00124 log(DEBUG,"Removing invites"); -00125 if (channel) +00115 +00116 char* userrec::GetFullRealHost() +00117 { +00118 static char fresult[MAXBUF]; +00119 snprintf(fresult,MAXBUF,"%s!%s@%s",nick,ident,host); +00120 return fresult; +00121 } +00122 +00123 bool userrec::IsInvited(irc::string &channel) +00124 { +00125 for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) 00126 { -00127 if (invites.size()) -00128 { -00129 for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) -00130 { -00131 if (i->channel) -00132 { -00133 if (!strcasecmp(i->channel,channel)) -00134 { -00135 invites.erase(i); -00136 return; -00137 } -00138 } -00139 } -00140 } -00141 } -00142 } -00143 -00144 bool userrec::HasPermission(char* command) -00145 { -00146 char TypeName[MAXBUF],Classes[MAXBUF],ClassName[MAXBUF],CommandList[MAXBUF]; -00147 char* mycmd; -00148 char* savept; -00149 char* savept2; -00150 -00151 // users on u-lined servers can completely bypass -00152 // all permissions based checks. -00153 // -00154 // of course, if this is sent to a remote server and this -00155 // server is not ulined there, then that other server -00156 // silently drops the command. -00157 if (is_uline(this->server)) -00158 return true; -00159 -00160 // are they even an oper at all? -00161 if (strchr(this->modes,'o')) -00162 { -00163 for (int j =0; j < Config->ConfValueEnum("type",&Config->config_f); j++) -00164 { -00165 Config->ConfValue("type","name",j,TypeName,&Config->config_f); -00166 if (!strcmp(TypeName,this->oper)) -00167 { -00168 Config->ConfValue("type","classes",j,Classes,&Config->config_f); -00169 char* myclass = strtok_r(Classes," ",&savept); -00170 while (myclass) -00171 { -00172 for (int k =0; k < Config->ConfValueEnum("class",&Config->config_f); k++) -00173 { -00174 Config->ConfValue("class","name",k,ClassName,&Config->config_f); -00175 if (!strcmp(ClassName,myclass)) -00176 { -00177 Config->ConfValue("class","commands",k,CommandList,&Config->config_f); -00178 mycmd = strtok_r(CommandList," ",&savept2); -00179 while (mycmd) -00180 { -00181 if ((!strcasecmp(mycmd,command)) || (*mycmd == '*')) -00182 { -00183 return true; -00184 } -00185 mycmd = strtok_r(NULL," ",&savept2); -00186 } -00187 } -00188 } -00189 myclass = strtok_r(NULL," ",&savept); -00190 } -00191 } -00192 } -00193 } -00194 return false; -00195 } -00196 -00197 -00198 bool userrec::AddBuffer(std::string a) -00199 { -00200 std::string b = ""; -00201 for (unsigned int i = 0; i < a.length(); i++) -00202 if ((a[i] != '\r') && (a[i] != '\0') && (a[i] != 7)) -00203 b = b + a[i]; -00204 std::stringstream stream(recvq); -00205 stream << b; -00206 recvq = stream.str(); -00207 unsigned int i = 0; -00208 // count the size of the first line in the buffer. -00209 while (i < recvq.length()) -00210 { -00211 if (recvq[i++] == '\n') -00212 break; -00213 } -00214 if (recvq.length() > (unsigned)this->recvqmax) -00215 { -00216 this->SetWriteError("RecvQ exceeded"); -00217 WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax); -00218 } -00219 // return false if we've had more than 600 characters WITHOUT -00220 // a carriage return (this is BAD, drop the socket) -00221 return (i < 600); -00222 } -00223 -00224 bool userrec::BufferIsReady() -00225 { -00226 for (unsigned int i = 0; i < recvq.length(); i++) -00227 if (recvq[i] == '\n') -00228 return true; -00229 return false; -00230 } -00231 -00232 void userrec::ClearBuffer() -00233 { -00234 recvq = ""; -00235 } -00236 -00237 std::string userrec::GetBuffer() -00238 { -00239 if (recvq == "") -00240 return ""; -00241 char* line = (char*)recvq.c_str(); -00242 std::string ret = ""; -00243 while ((*line != '\n') && (strlen(line))) -00244 { -00245 ret = ret + *line; -00246 line++; -00247 } -00248 if ((*line == '\n') || (*line == '\r')) -00249 line++; -00250 recvq = line; -00251 return ret; -00252 } -00253 -00254 void userrec::AddWriteBuf(std::string data) -00255 { -00256 if (this->GetWriteError() != "") -00257 return; -00258 if (sendq.length() + data.length() > (unsigned)this->sendqmax) -00259 { -00260 WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax); -00261 this->SetWriteError("SendQ exceeded"); -00262 return; -00263 } -00264 std::stringstream stream; -00265 stream << sendq << data; -00266 sendq = stream.str(); -00267 } -00268 -00269 // send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it) -00270 void userrec::FlushWriteBuf() -00271 { -00272 if (sendq.length()) -00273 { -00274 char* tb = (char*)this->sendq.c_str(); -00275 int n_sent = write(this->fd,tb,this->sendq.length()); -00276 if (n_sent == -1) -00277 { -00278 this->SetWriteError(strerror(errno)); -00279 } -00280 else -00281 { -00282 // advance the queue -00283 tb += n_sent; -00284 this->sendq = tb; -00285 // update the user's stats counters -00286 this->bytes_out += n_sent; -00287 this->cmds_out++; -00288 } -00289 } -00290 } -00291 -00292 void userrec::SetWriteError(std::string error) -00293 { -00294 log(DEBUG,"Setting error string for %s to '%s'",this->nick,error.c_str()); -00295 // don't try to set the error twice, its already set take the first string. -00296 if (this->WriteError == "") -00297 this->WriteError = error; -00298 } -00299 -00300 std::string userrec::GetWriteError() -00301 { -00302 return this->WriteError; -00303 } -
Generated on Thu Dec 15 11:14:14 2005 for InspIRCd by  +00127 irc::string compare = i->channel; +00128 if (compare == channel) +00129 { +00130 return true; +00131 } +00132 } +00133 return false; +00134 } +00135 +00136 InvitedList* userrec::GetInviteList() +00137 { +00138 return &invites; +00139 } +00140 +00141 void userrec::InviteTo(irc::string &channel) +00142 { +00143 Invited i; +00144 i.channel = channel; +00145 invites.push_back(i); +00146 } +00147 +00148 void userrec::RemoveInvite(irc::string &channel) +00149 { +00150 log(DEBUG,"Removing invites"); +00151 if (invites.size()) +00152 { +00153 for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) +00154 { +00155 irc::string compare = i->channel; +00156 if (compare == channel) +00157 { +00158 invites.erase(i); +00159 return; +00160 } +00161 } +00162 } +00163 } +00164 +00165 bool userrec::HasPermission(std::string &command) +00166 { +00167 char TypeName[MAXBUF],Classes[MAXBUF],ClassName[MAXBUF],CommandList[MAXBUF]; +00168 char* mycmd; +00169 char* savept; +00170 char* savept2; +00171 +00172 // users on u-lined servers can completely bypass +00173 // all permissions based checks. +00174 // +00175 // of course, if this is sent to a remote server and this +00176 // server is not ulined there, then that other server +00177 // silently drops the command. +00178 if (is_uline(this->server)) +00179 return true; +00180 +00181 // are they even an oper at all? +00182 if (strchr(this->modes,'o')) +00183 { +00184 for (int j =0; j < Config->ConfValueEnum("type",&Config->config_f); j++) +00185 { +00186 Config->ConfValue("type","name",j,TypeName,&Config->config_f); +00187 if (!strcmp(TypeName,this->oper)) +00188 { +00189 Config->ConfValue("type","classes",j,Classes,&Config->config_f); +00190 char* myclass = strtok_r(Classes," ",&savept); +00191 while (myclass) +00192 { +00193 for (int k =0; k < Config->ConfValueEnum("class",&Config->config_f); k++) +00194 { +00195 Config->ConfValue("class","name",k,ClassName,&Config->config_f); +00196 if (!strcmp(ClassName,myclass)) +00197 { +00198 Config->ConfValue("class","commands",k,CommandList,&Config->config_f); +00199 mycmd = strtok_r(CommandList," ",&savept2); +00200 while (mycmd) +00201 { +00202 if ((!strcasecmp(mycmd,command.c_str())) || (*mycmd == '*')) +00203 { +00204 return true; +00205 } +00206 mycmd = strtok_r(NULL," ",&savept2); +00207 } +00208 } +00209 } +00210 myclass = strtok_r(NULL," ",&savept); +00211 } +00212 } +00213 } +00214 } +00215 return false; +00216 } +00217 +00218 +00219 bool userrec::AddBuffer(std::string a) +00220 { +00221 std::string b = ""; +00222 for (unsigned int i = 0; i < a.length(); i++) +00223 if ((a[i] != '\r') && (a[i] != '\0') && (a[i] != 7)) +00224 b = b + a[i]; +00225 std::stringstream stream(recvq); +00226 stream << b; +00227 recvq = stream.str(); +00228 unsigned int i = 0; +00229 // count the size of the first line in the buffer. +00230 while (i < recvq.length()) +00231 { +00232 if (recvq[i++] == '\n') +00233 break; +00234 } +00235 if (recvq.length() > (unsigned)this->recvqmax) +00236 { +00237 this->SetWriteError("RecvQ exceeded"); +00238 WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax); +00239 } +00240 // return false if we've had more than 600 characters WITHOUT +00241 // a carriage return (this is BAD, drop the socket) +00242 return (i < 600); +00243 } +00244 +00245 bool userrec::BufferIsReady() +00246 { +00247 for (unsigned int i = 0; i < recvq.length(); i++) +00248 if (recvq[i] == '\n') +00249 return true; +00250 return false; +00251 } +00252 +00253 void userrec::ClearBuffer() +00254 { +00255 recvq = ""; +00256 } +00257 +00258 std::string userrec::GetBuffer() +00259 { +00260 if (recvq == "") +00261 return ""; +00262 char* line = (char*)recvq.c_str(); +00263 std::string ret = ""; +00264 while ((*line != '\n') && (strlen(line))) +00265 { +00266 ret = ret + *line; +00267 line++; +00268 } +00269 if ((*line == '\n') || (*line == '\r')) +00270 line++; +00271 recvq = line; +00272 return ret; +00273 } +00274 +00275 void userrec::AddWriteBuf(std::string data) +00276 { +00277 if (this->GetWriteError() != "") +00278 return; +00279 if (sendq.length() + data.length() > (unsigned)this->sendqmax) +00280 { +00281 /* Fix by brain - Set the error text BEFORE calling writeopers, because +00282 * if we dont it'll recursively call here over and over again trying +00283 * to repeatedly add the text to the sendq! +00284 */ +00285 this->SetWriteError("SendQ exceeded"); +00286 WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax); +00287 return; +00288 } +00289 std::stringstream stream; +00290 stream << sendq << data; +00291 sendq = stream.str(); +00292 } +00293 +00294 // send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it) +00295 void userrec::FlushWriteBuf() +00296 { +00297 if (sendq.length()) +00298 { +00299 char* tb = (char*)this->sendq.c_str(); +00300 int n_sent = write(this->fd,tb,this->sendq.length()); +00301 if (n_sent == -1) +00302 { +00303 this->SetWriteError(strerror(errno)); +00304 } +00305 else +00306 { +00307 // advance the queue +00308 tb += n_sent; +00309 this->sendq = tb; +00310 // update the user's stats counters +00311 this->bytes_out += n_sent; +00312 this->cmds_out++; +00313 } +00314 } +00315 } +00316 +00317 void userrec::SetWriteError(std::string error) +00318 { +00319 log(DEBUG,"Setting error string for %s to '%s'",this->nick,error.c_str()); +00320 // don't try to set the error twice, its already set take the first string. +00321 if (this->WriteError == "") +00322 this->WriteError = error; +00323 } +00324 +00325 std::string userrec::GetWriteError() +00326 { +00327 return this->WriteError; +00328 } +00329 +00330 void AddOper(userrec* user) +00331 { +00332 log(DEBUG,"Oper added to optimization list"); +00333 all_opers.push_back(user); +00334 } +00335 +00336 void DeleteOper(userrec* user) +00337 { +00338 for (std::vector<userrec*>::iterator a = all_opers.begin(); a < all_opers.end(); a++) +00339 { +00340 if (*a == user) +00341 { +00342 log(DEBUG,"Oper removed from optimization list"); +00343 all_opers.erase(a); +00344 return; +00345 } +00346 } +00347 } +00348 +00349 void kill_link(userrec *user,const char* r) +00350 { +00351 user_hash::iterator iter = clientlist.find(user->nick); +00352 +00353 char reason[MAXBUF]; +00354 +00355 strncpy(reason,r,MAXBUF); +00356 +00357 if (strlen(reason)>MAXQUIT) +00358 { +00359 reason[MAXQUIT-1] = '\0'; +00360 } +00361 +00362 log(DEBUG,"kill_link: %s '%s'",user->nick,reason); +00363 Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason); +00364 log(DEBUG,"closing fd %lu",(unsigned long)user->fd); +00365 +00366 if (user->registered == 7) { +00367 FOREACH_MOD OnUserQuit(user,reason); +00368 WriteCommonExcept(user,"QUIT :%s",reason); +00369 } +00370 +00371 user->FlushWriteBuf(); +00372 +00373 FOREACH_MOD OnUserDisconnect(user); +00374 +00375 if (user->fd > -1) +00376 { +00377 if (Config->GetIOHook(user->port)) +00378 { +00379 Config->GetIOHook(user->port)->OnRawSocketClose(user->fd); +00380 } +00381 ServerInstance->SE->DelFd(user->fd); +00382 user->CloseSocket(); +00383 } +00384 +00385 // this must come before the WriteOpers so that it doesnt try to fill their buffer with anything +00386 // if they were an oper with +s. +00387 if (user->registered == 7) { +00388 purge_empty_chans(user); +00389 // fix by brain: only show local quits because we only show local connects (it just makes SENSE) +00390 if (user->fd > -1) +00391 WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason); +00392 AddWhoWas(user); +00393 } +00394 +00395 if (iter != clientlist.end()) +00396 { +00397 log(DEBUG,"deleting user hash value %lu",(unsigned long)user); +00398 if (user->fd > -1) +00399 { +00400 fd_ref_table[user->fd] = NULL; +00401 if (find(local_users.begin(),local_users.end(),user) != local_users.end()) +00402 { +00403 local_users.erase(find(local_users.begin(),local_users.end(),user)); +00404 log(DEBUG,"Delete local user"); +00405 } +00406 } +00407 clientlist.erase(iter); +00408 } +00409 delete user; +00410 } +00411 +00412 void kill_link_silent(userrec *user,const char* r) +00413 { +00414 user_hash::iterator iter = clientlist.find(user->nick); +00415 +00416 char reason[MAXBUF]; +00417 +00418 strncpy(reason,r,MAXBUF); +00419 +00420 if (strlen(reason)>MAXQUIT) +00421 { +00422 reason[MAXQUIT-1] = '\0'; +00423 } +00424 +00425 log(DEBUG,"kill_link: %s '%s'",user->nick,reason); +00426 Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason); +00427 log(DEBUG,"closing fd %lu",(unsigned long)user->fd); +00428 +00429 user->FlushWriteBuf(); +00430 +00431 if (user->registered == 7) { +00432 FOREACH_MOD OnUserQuit(user,reason); +00433 WriteCommonExcept(user,"QUIT :%s",reason); +00434 } +00435 +00436 FOREACH_MOD OnUserDisconnect(user); +00437 +00438 if (user->fd > -1) +00439 { +00440 if (Config->GetIOHook(user->port)) +00441 { +00442 Config->GetIOHook(user->port)->OnRawSocketClose(user->fd); +00443 } +00444 ServerInstance->SE->DelFd(user->fd); +00445 user->CloseSocket(); +00446 } +00447 +00448 if (user->registered == 7) { +00449 purge_empty_chans(user); +00450 } +00451 +00452 if (iter != clientlist.end()) +00453 { +00454 log(DEBUG,"deleting user hash value %lu",(unsigned long)user); +00455 if (user->fd > -1) +00456 { +00457 fd_ref_table[user->fd] = NULL; +00458 if (find(local_users.begin(),local_users.end(),user) != local_users.end()) +00459 { +00460 log(DEBUG,"Delete local user"); +00461 local_users.erase(find(local_users.begin(),local_users.end(),user)); +00462 } +00463 } +00464 clientlist.erase(iter); +00465 } +00466 delete user; +00467 } +00468 +00469 +00470 /* adds or updates an entry in the whowas list */ +00471 void AddWhoWas(userrec* u) +00472 { +00473 whowas_hash::iterator iter = whowas.find(u->nick); +00474 WhoWasUser *a = new WhoWasUser(); +00475 strlcpy(a->nick,u->nick,NICKMAX); +00476 strlcpy(a->ident,u->ident,IDENTMAX); +00477 strlcpy(a->dhost,u->dhost,160); +00478 strlcpy(a->host,u->host,160); +00479 strlcpy(a->fullname,u->fullname,MAXGECOS); +00480 strlcpy(a->server,u->server,256); +00481 a->signon = u->signon; +00482 +00483 /* MAX_WHOWAS: max number of /WHOWAS items +00484 * WHOWAS_STALE: number of hours before a WHOWAS item is marked as stale and +00485 * can be replaced by a newer one +00486 */ +00487 +00488 if (iter == whowas.end()) +00489 { +00490 if (whowas.size() >= (unsigned)WHOWAS_MAX) +00491 { +00492 for (whowas_hash::iterator i = whowas.begin(); i != whowas.end(); i++) +00493 { +00494 // 3600 seconds in an hour ;) +00495 if ((i->second->signon)<(TIME-(WHOWAS_STALE*3600))) +00496 { +00497 // delete the old one +00498 if (i->second) delete i->second; +00499 // replace with new one +00500 i->second = a; +00501 log(DEBUG,"added WHOWAS entry, purged an old record"); +00502 return; +00503 } +00504 } +00505 // no space left and user doesnt exist. Don't leave ram in use! +00506 log(DEBUG,"Not able to update whowas (list at WHOWAS_MAX entries and trying to add new?), freeing excess ram"); +00507 delete a; +00508 } +00509 else +00510 { +00511 log(DEBUG,"added fresh WHOWAS entry"); +00512 whowas[a->nick] = a; +00513 } +00514 } +00515 else +00516 { +00517 log(DEBUG,"updated WHOWAS entry"); +00518 if (iter->second) delete iter->second; +00519 iter->second = a; +00520 } +00521 } +00522 +00523 /* add a client connection to the sockets list */ +00524 void AddClient(int socket, char* host, int port, bool iscached, char* ip) +00525 { +00526 string tempnick; +00527 char tn2[MAXBUF]; +00528 user_hash::iterator iter; +00529 +00530 tempnick = ConvToStr(socket) + "-unknown"; +00531 sprintf(tn2,"%lu-unknown",(unsigned long)socket); +00532 +00533 iter = clientlist.find(tempnick); +00534 +00535 // fix by brain. +00536 // as these nicknames are 'RFC impossible', we can be sure nobody is going to be +00537 // using one as a registered connection. As theyre per fd, we can also safely assume +00538 // that we wont have collisions. Therefore, if the nick exists in the list, its only +00539 // used by a dead socket, erase the iterator so that the new client may reclaim it. +00540 // this was probably the cause of 'server ignores me when i hammer it with reconnects' +00541 // issue in earlier alphas/betas +00542 if (iter != clientlist.end()) +00543 { +00544 userrec* goner = iter->second; +00545 delete goner; +00546 clientlist.erase(iter); +00547 } +00548 +00549 /* +00550 * It is OK to access the value here this way since we know +00551 * it exists, we just created it above. +00552 * +00553 * At NO other time should you access a value in a map or a +00554 * hash_map this way. +00555 */ +00556 clientlist[tempnick] = new userrec(); +00557 +00558 log(DEBUG,"AddClient: %lu %s %d %s",(unsigned long)socket,host,port,ip); +00559 +00560 clientlist[tempnick]->fd = socket; +00561 strlcpy(clientlist[tempnick]->nick, tn2,NICKMAX); +00562 strlcpy(clientlist[tempnick]->host, host,160); +00563 strlcpy(clientlist[tempnick]->dhost, host,160); +00564 clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName); +00565 strlcpy(clientlist[tempnick]->ident, "unknown",IDENTMAX); +00566 clientlist[tempnick]->registered = 0; +00567 clientlist[tempnick]->signon = TIME + Config->dns_timeout; +00568 clientlist[tempnick]->lastping = 1; +00569 clientlist[tempnick]->port = port; +00570 strlcpy(clientlist[tempnick]->ip,ip,16); +00571 +00572 // set the registration timeout for this user +00573 unsigned long class_regtimeout = 90; +00574 int class_flood = 0; +00575 long class_threshold = 5; +00576 long class_sqmax = 262144; // 256kb +00577 long class_rqmax = 4096; // 4k +00578 +00579 for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++) +00580 { +00581 if (match(clientlist[tempnick]->host,i->host) && (i->type == CC_ALLOW)) +00582 { +00583 class_regtimeout = (unsigned long)i->registration_timeout; +00584 class_flood = i->flood; +00585 clientlist[tempnick]->pingmax = i->pingtime; +00586 class_threshold = i->threshold; +00587 class_sqmax = i->sendqmax; +00588 class_rqmax = i->recvqmax; +00589 break; +00590 } +00591 } +00592 +00593 clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax + Config->dns_timeout; +00594 clientlist[tempnick]->timeout = TIME+class_regtimeout; +00595 clientlist[tempnick]->flood = class_flood; +00596 clientlist[tempnick]->threshold = class_threshold; +00597 clientlist[tempnick]->sendqmax = class_sqmax; +00598 clientlist[tempnick]->recvqmax = class_rqmax; +00599 +00600 ucrec a; +00601 a.channel = NULL; +00602 a.uc_modes = 0; +00603 for (int i = 0; i < MAXCHANS; i++) +00604 clientlist[tempnick]->chans.push_back(a); +00605 +00606 if (clientlist.size() > Config->SoftLimit) +00607 { +00608 kill_link(clientlist[tempnick],"No more connections allowed"); +00609 return; +00610 } +00611 +00612 if (clientlist.size() >= MAXCLIENTS) +00613 { +00614 kill_link(clientlist[tempnick],"No more connections allowed"); +00615 return; +00616 } +00617 +00618 // this is done as a safety check to keep the file descriptors within range of fd_ref_table. +00619 // its a pretty big but for the moment valid assumption: +00620 // file descriptors are handed out starting at 0, and are recycled as theyre freed. +00621 // therefore if there is ever an fd over 65535, 65536 clients must be connected to the +00622 // irc server at once (or the irc server otherwise initiating this many connections, files etc) +00623 // which for the time being is a physical impossibility (even the largest networks dont have more +00624 // than about 10,000 users on ONE server!) +00625 if ((unsigned)socket > 65534) +00626 { +00627 kill_link(clientlist[tempnick],"Server is full"); +00628 return; +00629 } +00630 char* e = matches_exception(ip); +00631 if (!e) +00632 { +00633 char* r = matches_zline(ip); +00634 if (r) +00635 { +00636 char reason[MAXBUF]; +00637 snprintf(reason,MAXBUF,"Z-Lined: %s",r); +00638 kill_link(clientlist[tempnick],reason); +00639 return; +00640 } +00641 } +00642 fd_ref_table[socket] = clientlist[tempnick]; +00643 local_users.push_back(clientlist[tempnick]); +00644 ServerInstance->SE->AddFd(socket,true,X_ESTAB_CLIENT); +00645 } +00646 +00647 void FullConnectUser(userrec* user) +00648 { +00649 ServerInstance->stats->statsConnects++; +00650 user->idle_lastmsg = TIME; +00651 log(DEBUG,"ConnectUser: %s",user->nick); +00652 +00653 if ((strcmp(Passwd(user),"")) && (!user->haspassed)) +00654 { +00655 kill_link(user,"Invalid password"); +00656 return; +00657 } +00658 if (IsDenied(user)) +00659 { +00660 kill_link(user,"Unauthorised connection"); +00661 return; +00662 } +00663 +00664 char match_against[MAXBUF]; +00665 snprintf(match_against,MAXBUF,"%s@%s",user->ident,user->host); +00666 char* e = matches_exception(match_against); +00667 if (!e) +00668 { +00669 char* r = matches_gline(match_against); +00670 if (r) +00671 { +00672 char reason[MAXBUF]; +00673 snprintf(reason,MAXBUF,"G-Lined: %s",r); +00674 kill_link_silent(user,reason); +00675 return; +00676 } +00677 r = matches_kline(user->host); +00678 if (r) +00679 { +00680 char reason[MAXBUF]; +00681 snprintf(reason,MAXBUF,"K-Lined: %s",r); +00682 kill_link_silent(user,reason); +00683 return; +00684 } +00685 } +00686 +00687 +00688 WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Config->Network); +00689 WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host); +00690 WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION); +00691 WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__); +00692 WriteServ(user->fd,"004 %s %s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,Config->ServerName,VERSION); +00693 // the neatest way to construct the initial 005 numeric, considering the number of configure constants to go in it... +00694 std::stringstream v; +00695 v << "WALLCHOPS MODES=13 CHANTYPES=# PREFIX=(ohv)@%+ MAP SAFELIST MAXCHANNELS=" << MAXCHANS; +00696 v << " MAXBANS=60 NICKLEN=" << NICKMAX; +00697 v << " TOPICLEN=" << MAXTOPIC << " KICKLEN=" << MAXKICK << " MAXTARGETS=20 AWAYLEN=" << MAXAWAY << " CHANMODES=ohvb,k,l,psmnti NETWORK="; +00698 v << Config->Network; +00699 std::string data005 = v.str(); +00700 FOREACH_MOD On005Numeric(data005); +00701 // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line... +00702 // so i'd better split it :) +00703 std::stringstream out(data005); +00704 std::string token = ""; +00705 std::string line5 = ""; +00706 int token_counter = 0; +00707 while (!out.eof()) +00708 { +00709 out >> token; +00710 line5 = line5 + token + " "; +00711 token_counter++; +00712 if ((token_counter >= 13) || (out.eof() == true)) +00713 { +00714 WriteServ(user->fd,"005 %s %s:are supported by this server",user->nick,line5.c_str()); +00715 line5 = ""; +00716 token_counter = 0; +00717 } +00718 } +00719 ShowMOTD(user); +00720 +00721 // fix 3 by brain, move registered = 7 below these so that spurious modes and host changes dont go out +00722 // onto the network and produce 'fake direction' +00723 FOREACH_MOD OnUserConnect(user); +00724 FOREACH_MOD OnGlobalConnect(user); +00725 user->registered = 7; +00726 WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,user->ip); +00727 } +00728 +00729 +00730 /* shows the message of the day, and any other on-logon stuff */ +00731 void ConnectUser(userrec *user) +00732 { +00733 // dns is already done, things are fast. no need to wait for dns to complete just pass them straight on +00734 if ((user->dns_done) && (user->registered >= 3) && (AllModulesReportReady(user))) +00735 { +00736 FullConnectUser(user); +00737 } +00738 } +00739 +00740 /* re-allocates a nick in the user_hash after they change nicknames, +00741 * returns a pointer to the new user as it may have moved */ +00742 +00743 userrec* ReHashNick(char* Old, char* New) +00744 { +00745 //user_hash::iterator newnick; +00746 user_hash::iterator oldnick = clientlist.find(Old); +00747 +00748 log(DEBUG,"ReHashNick: %s %s",Old,New); +00749 +00750 if (!strcasecmp(Old,New)) +00751 { +00752 log(DEBUG,"old nick is new nick, skipping"); +00753 return oldnick->second; +00754 } +00755 +00756 if (oldnick == clientlist.end()) return NULL; /* doesnt exist */ +00757 +00758 log(DEBUG,"ReHashNick: Found hashed nick %s",Old); +00759 +00760 userrec* olduser = oldnick->second; +00761 clientlist[New] = olduser; +00762 clientlist.erase(oldnick); +00763 +00764 log(DEBUG,"ReHashNick: Nick rehashed as %s",New); +00765 +00766 return clientlist[New]; +00767 } +00768 +00769 void force_nickchange(userrec* user,const char* newnick) +00770 { +00771 char nick[MAXBUF]; +00772 int MOD_RESULT = 0; +00773 +00774 strcpy(nick,""); +00775 +00776 FOREACH_RESULT(OnUserPreNick(user,newnick)); +00777 if (MOD_RESULT) { +00778 ServerInstance->stats->statsCollisions++; +00779 kill_link(user,"Nickname collision"); +00780 return; +00781 } +00782 if (matches_qline(newnick)) +00783 { +00784 ServerInstance->stats->statsCollisions++; +00785 kill_link(user,"Nickname collision"); +00786 return; +00787 } +00788 +00789 if (user) +00790 { +00791 if (newnick) +00792 { +00793 strncpy(nick,newnick,MAXBUF); +00794 } +00795 if (user->registered == 7) +00796 { +00797 char* pars[1]; +00798 pars[0] = nick; +00799 std::string cmd = "NICK"; +00800 ServerInstance->Parser->CallHandler(cmd,pars,1,user); +00801 } +00802 } +00803 } +00804 +
Generated on Mon Dec 19 18:02:13 2005 for InspIRCd by  doxygen 1.4.4-20050815
-- cgit v1.3.1-10-gc9f91