- }
- }
- }
- // if the user was not in any channels, no users will receive the text. Make sure the user
- // receives their OWN message for WriteCommon
- if (!sent_to_at_least_one)
- {
- WriteFrom(u->fd,u,"%s",textbuffer);
- }
-}
-
-/* write a formatted string to all users who share at least one common
- * channel, NOT including the source user e.g. for use in QUIT */
-
-void WriteCommonExcept(userrec *u, char* text, ...)
-{
- if (!u)
- {
- log(DEFAULT,"*** BUG *** WriteCommon was given an invalid parameter");
- return;
- }
-
- if (u->registered != 7) {
- log(DEFAULT,"*** BUG *** WriteCommon on an unregistered user");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- bzero(&already_sent,65536);
-
- for (int i = 0; i < MAXCHANS; i++)
- {
- if (u->chans[i].channel)
- {
- std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* otheruser = (userrec*)o;
- if (u != otheruser)
- {
- if ((otheruser->fd > 0) && (!already_sent[otheruser->fd]))
- {
- already_sent[otheruser->fd] = 1;
- WriteFrom(otheruser->fd,u,"%s",textbuffer);
- }
- }
- }
- }
- }
-}
-
-void WriteOpers(char* text, ...)
-{
- if (!text)
- {
- log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
- {
- userrec* a = *i;
- if ((a) && (a->fd != FD_MAGIC_NUMBER))
- {
- if (strchr(a->modes,'s'))
- {
- // send server notices to all with +s
- WriteServ(a->fd,"NOTICE %s :%s",a->nick,textbuffer);
- }
- }
- }
-}
-
-void NoticeAllOpers(userrec *source, bool local_only, char* text, ...)
-{
- if ((!text) || (!source))
- {
- log(DEFAULT,"*** BUG *** NoticeAllOpers was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- for (std::vector<userrec*>::iterator i = all_opers.begin(); i != all_opers.end(); i++)
- {
- userrec* a = *i;
- if ((a) && (a->fd != FD_MAGIC_NUMBER))
- {
- if (strchr(a->modes,'s'))
- {
- // send server notices to all with +s
- WriteServ(a->fd,"NOTICE %s :*** Notice From %s: %s",a->nick,source->nick,textbuffer);
- }
- }
- }
-
- if (!local_only)
- {
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"V %s @* :%s",source->nick,textbuffer);
- NetSendToAll(buffer);
- }
-}
-
-// returns TRUE of any users on channel C occupy server 'servername'.
-
-bool ChanAnyOnThisServer(chanrec *c,char* servername)
-{
- log(DEBUG,"ChanAnyOnThisServer");
-
- std::vector<char*> *ulist = c->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* user = (userrec*)o;
- if (!strcasecmp(user->server,servername))
- return true;
- }
- return false;
-}
-
-// returns true if user 'u' shares any common channels with any users on server 'servername'
-
-bool CommonOnThisServer(userrec* u,const char* servername)
-{
- log(DEBUG,"ChanAnyOnThisServer");
-
- for (int i = 0; i < MAXCHANS; i++)
- {
- if (u->chans[i].channel)
- {
- std::vector<char*> *ulist = u->chans[i].channel->GetUsers();
- for (int j = 0; j < ulist->size(); j++)
- {
- char* o = (*ulist)[j];
- userrec* user = (userrec*)o;
- if (!strcasecmp(user->server,servername))
- return true;
- }
- }
- }
- return false;
-}
-
-
-void NetSendToCommon(userrec* u, char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToCommon: '%s' '%s'",u->nick,s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (CommonOnThisServer(u,me[j]->connectors[k].GetServerName().c_str()))
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
- }
-}
-
-
-void NetSendToAll(char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToAll: '%s'",s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
-}
-
-void NetSendToAllAlive(char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToAllAlive: '%s'",s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (me[j]->connectors[k].GetState() != STATE_DISCONNECTED)
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- else
- {
- log(DEBUG,"%s is dead, not sending to it.",me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
- }
-}
-
-
-void NetSendToOne(char* target,char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToOne: '%s' '%s'",target,s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (!strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
- }
-}
-
-void NetSendToAllExcept(const char* target,char* s)
-{
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"%s",s);
-
- log(DEBUG,"NetSendToAllExcept: '%s' '%s'",target,s);
-
- std::string msg = buffer;
- FOREACH_MOD OnPacketTransmit(msg,s);
- strlcpy(buffer,msg.c_str(),MAXBUF);
-
- for (int j = 0; j < 32; j++)
- {
- if (me[j] != NULL)
- {
- for (int k = 0; k < me[j]->connectors.size(); k++)
- {
- if (strcasecmp(me[j]->connectors[k].GetServerName().c_str(),target))
- {
- me[j]->SendPacket(buffer,me[j]->connectors[k].GetServerName().c_str());
- }
- }
- }
- }
-}
-
-
-void WriteMode(const char* modes, int flags, const char* text, ...)
-{
- if ((!text) || (!modes) || (!flags))
- {
- log(DEFAULT,"*** BUG *** WriteMode was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
- int modelen = strlen(modes);
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
- {
- bool send_to_user = false;
-
- if (flags == WM_AND)
- {
- send_to_user = true;
- for (int n = 0; n < modelen; n++)
- {
- if (!hasumode(i->second,modes[n]))
- {
- send_to_user = false;
- break;
- }
- }
- }
- else if (flags == WM_OR)
- {
- send_to_user = false;
- for (int n = 0; n < modelen; n++)
- {
- if (hasumode(i->second,modes[n]))
- {
- send_to_user = true;
- break;
- }
- }
- }
-
- if (send_to_user)
- {
- WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer);
- }
- }
- }
-}
-
-
-void NoticeAll(userrec *source, bool local_only, char* text, ...)
-{
- if ((!text) || (!source))
- {
- log(DEFAULT,"*** BUG *** NoticeAll was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
- {
- WriteFrom(i->second->fd,source,"NOTICE $* :%s",textbuffer);
- }
- }
-
- if (!local_only)
- {
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"V %s * :%s",source->nick,textbuffer);
- NetSendToAll(buffer);
- }
-
-}
-
-void WriteWallOps(userrec *source, bool local_only, char* text, ...)
-{
- if ((!text) || (!source))
- {
- log(DEFAULT,"*** BUG *** WriteOpers was given an invalid parameter");
- return;
- }
-
- char textbuffer[MAXBUF];
- va_list argsPtr;
- va_start (argsPtr, text);
- vsnprintf(textbuffer, MAXBUF, text, argsPtr);
- va_end(argsPtr);
-
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if ((i->second) && (i->second->fd != FD_MAGIC_NUMBER))
- {
- if (strchr(i->second->modes,'w'))
- {
- WriteTo(source,i->second,"WALLOPS :%s",textbuffer);
- }
- }
- }
-
- if (!local_only)
- {
- char buffer[MAXBUF];
- snprintf(buffer,MAXBUF,"@ %s :%s",source->nick,textbuffer);
- NetSendToAll(buffer);
- }
-}
-
-/* convert a string to lowercase. Note following special circumstances
- * taken from RFC 1459. Many "official" server branches still hold to this
- * rule so i will too;
- *
- * Because of IRC's scandanavian origin, the characters {}| are
- * considered to be the lower case equivalents of the characters []\,
- * respectively. This is a critical issue when determining the
- * equivalence of two nicknames.
- */
-
-void strlower(char *n)
-{
- if (n)
- {
- for (char* t = n; *t; t++)
- *t = lowermap[*t];
- }
-}
-
-
-
-/* Find a user record by nickname and return a pointer to it */
-
-userrec* Find(std::string nick)
-{
- user_hash::iterator iter = clientlist.find(nick);
-
- if (iter == clientlist.end())
- /* Couldn't find it */
- return NULL;
-
- return iter->second;
-}
-
-/* find a channel record by channel name and return a pointer to it */
-
-chanrec* FindChan(const char* chan)
-{
- if (!chan)
- {
- log(DEFAULT,"*** BUG *** Findchan was given an invalid parameter");
- return NULL;
- }
-
- chan_hash::iterator iter = chanlist.find(chan);
-
- if (iter == chanlist.end())
- /* Couldn't find it */
- return NULL;
-
- return iter->second;
-}
-
-
-long GetMaxBans(char* name)
-{
- char CM[MAXBUF];
- for (int count = 0; count < ConfValueEnum("banlist",&config_f); count++)
- {
- ConfValue("banlist","chan",count,CM,&config_f);
- if (match(name,CM))
- {
- ConfValue("banlist","limit",count,CM,&config_f);
- return atoi(CM);
- }
- }
- return 64;
-}
-
-
-void purge_empty_chans(userrec* u)
-{
-
- int go_again = 1, purge = 0;
-
- // firstly decrement the count on each channel
- for (int f = 0; f < MAXCHANS; f++)
- {
- if (u->chans[f].channel)
- {
- u->chans[f].channel->DelUser((char*)u);
- }
- }
-
- for (int i = 0; i < MAXCHANS; i++)
- {
- if (u->chans[i].channel)
- {
- if (!usercount(u->chans[i].channel))
- {
- chan_hash::iterator i2 = chanlist.find(u->chans[i].channel->name);
- /* kill the record */
- if (i2 != chanlist.end())
- {
- log(DEBUG,"del_channel: destroyed: %s",i2->second->name);
- if (i2->second)
- delete i2->second;
- chanlist.erase(i2);
- go_again = 1;
- purge++;
- u->chans[i].channel = NULL;
- }
- }
- else
- {
- log(DEBUG,"skipped purge for %s",u->chans[i].channel->name);
- }
- }
- }
- log(DEBUG,"completed channel purge, killed %lu",(unsigned long)purge);
-
- DeleteOper(u);
-}
-
-
-char scratch[MAXBUF];
-char sparam[MAXBUF];
-
-char* chanmodes(chanrec *chan)
-{
- if (!chan)
- {
- log(DEFAULT,"*** BUG *** chanmodes was given an invalid parameter");
- strcpy(scratch,"");
- return scratch;
- }
-
- strcpy(scratch,"");
- strcpy(sparam,"");
- if (chan->noexternal)
- {
- strlcat(scratch,"n",MAXMODES);
- }
- if (chan->topiclock)
- {
- strlcat(scratch,"t",MAXMODES);
- }
- if (chan->key[0])
- {
- strlcat(scratch,"k",MAXMODES);
- }
- if (chan->limit)
- {
- strlcat(scratch,"l",MAXMODES);
- }
- if (chan->inviteonly)
- {
- strlcat(scratch,"i",MAXMODES);
- }
- if (chan->moderated)
- {
- strlcat(scratch,"m",MAXMODES);
- }
- if (chan->secret)
- {
- strlcat(scratch,"s",MAXMODES);
- }
- if (chan->c_private)
- {
- strlcat(scratch,"p",MAXMODES);
- }
- if (chan->key[0])
- {
- strlcat(sparam," ",MAXBUF);
- strlcat(sparam,chan->key,MAXBUF);
- }
- if (chan->limit)
- {
- char foo[24];
- sprintf(foo," %lu",(unsigned long)chan->limit);
- strlcat(sparam,foo,MAXBUF);
- }
- if (*chan->custom_modes)
- {
- strlcat(scratch,chan->custom_modes,MAXMODES);
- for (int z = 0; chan->custom_modes[z] != 0; z++)
- {
- std::string extparam = chan->GetModeParameter(chan->custom_modes[z]);
- if (extparam != "")
- {
- strlcat(sparam," ",MAXBUF);
- strlcat(sparam,extparam.c_str(),MAXBUF);
- }
- }
- }
- log(DEBUG,"chanmodes: %s %s%s",chan->name,scratch,sparam);
- strlcat(scratch,sparam,MAXMODES);
- return scratch;
-}
-
-
-/* compile a userlist of a channel into a string, each nick seperated by
- * spaces and op, voice etc status shown as @ and + */
-
-void userlist(userrec *user,chanrec *c)
-{
- if ((!c) || (!user))
- {
- log(DEFAULT,"*** BUG *** userlist was given an invalid parameter");
- return;
- }
-
- snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
-
- std::vector<char*> *ulist = c->GetUsers();
- for (int i = 0; i < ulist->size(); i++)
- {
- char* o = (*ulist)[i];
- userrec* otheruser = (userrec*)o;
- if ((!has_channel(user,c)) && (strchr(otheruser->modes,'i')))
- {
- /* user is +i, and source not on the channel, does not show
- * nick in NAMES list */
- continue;
- }
- strlcat(list,cmode(otheruser,c),MAXBUF);
- strlcat(list,otheruser->nick,MAXBUF);
- strlcat(list," ",MAXBUF);
- if (strlen(list)>(480-NICKMAX))
- {
- /* list overflowed into
- * multiple numerics */
- WriteServ(user->fd,"%s",list);
- snprintf(list,MAXBUF,"353 %s = %s :", user->nick, c->name);
- }
- }
- /* if whats left in the list isnt empty, send it */
- if (list[strlen(list)-1] != ':')
- {
- WriteServ(user->fd,"%s",list);
- }
-}
-
-/* return a count of the users on a specific channel accounting for
- * invisible users who won't increase the count. e.g. for /LIST */
-
-int usercount_i(chanrec *c)
-{
- int count = 0;
-
- if (!c)
- {
- log(DEFAULT,"*** BUG *** usercount_i was given an invalid parameter");
- return 0;
- }
-
- strcpy(list,"");
- for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++)
- {
- if (i->second)
- {
- if (has_channel(i->second,c))
- {
- if (isnick(i->second->nick))
- {
- if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i')))
- {
- /* user is +i, and source not on the channel, does not show
- * nick in NAMES list */
- continue;
- }
- count++;
- }
- }
- }
- }
- log(DEBUG,"usercount_i: %s %lu",c->name,(unsigned long)count);
- return count;
-}
-
-
-int usercount(chanrec *c)
-{
- if (!c)
- {
- log(DEFAULT,"*** BUG *** usercount was given an invalid parameter");
- return 0;
- }
- int count = c->GetUserCounter();
- log(DEBUG,"usercount: %s %lu",c->name,(unsigned long)count);
- return count;
-}
-
-
-/* add a channel to a user, creating the record for it if needed and linking
- * it to the user record */
-
-chanrec* add_channel(userrec *user, const char* cn, const char* key, bool override)
-{
- if ((!user) || (!cn))
- {
- log(DEFAULT,"*** BUG *** add_channel was given an invalid parameter");
- return 0;
- }
-
- chanrec* Ptr;
- int created = 0;
- char cname[MAXBUF];
-
- strncpy(cname,cn,MAXBUF);
-
- // we MUST declare this wherever we use FOREACH_RESULT
- int MOD_RESULT = 0;
-
- if (strlen(cname) > CHANMAX-1)
- {
- cname[CHANMAX-1] = '\0';
- }
-
- log(DEBUG,"add_channel: %s %s",user->nick,cname);
-
- if ((FindChan(cname)) && (has_channel(user,FindChan(cname))))
- {
- return NULL; // already on the channel!
- }
-
-
- if (!FindChan(cname))
- {
- MOD_RESULT = 0;
- FOREACH_RESULT(OnUserPreJoin(user,NULL,cname));
- if (MOD_RESULT == 1) {
- return NULL;
- }
-
- /* create a new one */
- log(DEBUG,"add_channel: creating: %s",cname);
- {
- chanlist[cname] = new chanrec();
-
- strlcpy(chanlist[cname]->name, cname,CHANMAX);
- chanlist[cname]->topiclock = 1;
- chanlist[cname]->noexternal = 1;
- chanlist[cname]->created = TIME;
- strcpy(chanlist[cname]->topic, "");
- strncpy(chanlist[cname]->setby, user->nick,NICKMAX);
- chanlist[cname]->topicset = 0;
- Ptr = chanlist[cname];
- log(DEBUG,"add_channel: created: %s",cname);
- /* set created to 2 to indicate user
- * is the first in the channel
- * and should be given ops */
- created = 2;
- }
- }
- else
- {
- /* channel exists, just fish out a pointer to its struct */
- Ptr = FindChan(cname);
- if (Ptr)
- {
- log(DEBUG,"add_channel: joining to: %s",Ptr->name);
-
- // the override flag allows us to bypass channel modes
- // and bans (used by servers)
- if ((!override) || (!strcasecmp(user->server,ServerName)))
- {
- log(DEBUG,"Not overriding...");
- MOD_RESULT = 0;
- FOREACH_RESULT(OnUserPreJoin(user,Ptr,cname));
- if (MOD_RESULT == 1) {
- return NULL;
- }
- log(DEBUG,"MOD_RESULT=%d",MOD_RESULT);
-
- if (!MOD_RESULT)