diff -c -r -N irc2.8.21+CSr15/README.CS irc2.8.21+CSr16/README.CS *** irc2.8.21+CSr15/README.CS Wed Dec 31 18:00:00 1969 --- irc2.8.21+CSr16/README.CS Tue Dec 19 21:15:29 1995 *************** *** 0 **** --- 1,18 ---- + + New in CSr16: + + 1) TSora - A timestamping protocal which disallows "op hacking" and nick + colliding. + Thanks to Roger Espel Llima + + 2) Better kline checking - This should be faster, and use less CPU + Thanks to Philippe Levan + + 3) Fixed /rehash not working when the server is in dog3's High Traffic Mode + + 4) Added nicknames to users.log + + 5) Upped values in dog3.h, config.h, and hash.c for larger sendqs and a + bigger hash table for clients. + + diff -c -r -N irc2.8.21+CSr15/README.TSora irc2.8.21+CSr16/README.TSora *** irc2.8.21+CSr15/README.TSora Wed Dec 31 18:00:00 1969 --- irc2.8.21+CSr16/README.TSora Sat Dec 16 18:52:11 1995 *************** *** 0 **** --- 1,320 ---- + Protocol changes for +TSora + --------------------------- + + + Note: + + The protocols described here implement TimeStamps on IRC channels and + nicks. The idea of IRC TimeStamps was started on Undernet, and first + implemented by Run . The protocols used here + are not exactly the same as the ones used on Undernet; the nick-kill + handling is very similar and must be credited to Run, while the + "TimeStamped channel description" protocol is quite different. + + + + TSora servers keep track of which version of the TS protocol (if any) + their neighboring servers are using, and take it into account when + sending messages to them. This allows for seamless integration of TS + servers into a non-TS net, and for upgrades of the protocol. + + Each server knows which is the lowest and the highest version of the + TS protocol it can interact with; currently both of these are set to 1: + + #define TS_CURRENT 1 /* the highest TS ver we can do */ + #define TS_MIN 1 /* the lowest TS ver we can do */ + + + Timings and TS versions: + ======================== + + . Keep a 'delta' value to be added to the result of all calls to time(), + initially 0. + + . Send a + + SVINFO : + + before "SERVER" and after "PASS", where is 1 if we're + connected to more TSora servers, and 0 if not, and is our + idea of the current UTC time, fixed with the delta. + + . When we receive a "SVINFO :" line from a connecting + server, we ignore it if TS_CURRENT if + z==0, and to (t-)/2 if z!=0. The SVINFO data is kept around + until the server has effectively registered with SERVER, and used + *after* sending our own SVINFO to that server. + + + Explanations: + + Servers will always know which of their directly-linked servers + can do TS, and will use the TS protocol only with servers that + do understand it. This makes it possible to switch to full TS + in just one code-replacement step, without incompatibilities. + + As long as not all servers are TS-aware, the net will be divided + into "zones" of linked TS-aware servers. Channel modes will be + kept synchronized at least within the zone in which the channel + was created, and nick collisions between servers in the same + zone will result in only one client being killed. + + Time synchronization ensures that servers have the same idea of the + current time, and achieves this purpose as long as TS servers are + introduced one by one within the same 'zone'. The merging of two zones + cannot synchronize them completely, but it is to be expected that + within each zone the effective time will be very close to the real + time. + + The current time is only used when setting a TS on a new channel or + nick, and once such a TS is set, it is never modified because of + synchronization, as it is much more important that the TS for a + channel or nick stays the same across all servers than that it is + accurate to the second. + + Note that Undernet's 2.8.x servers have no time synchronization at + all, and have had no problems because of it - all of this is more to + catch the occasional server with a way-off clock than anything. + + + NICK handling patches (anti-nick-collide + shorter connect burst): + ================================================================== + + . For each nick, store a TS value = the TS value received if any, or our + UTC+delta at the time we first heard of the nick. TS's are propagated + to TS-aware servers whenever sending a NICK command. + + . Nick changes reset the TS to the current time. + + . When sending a connect burst to another TS server, replace the + NICK/USER pair with only one NICK command containing the nick, the + hopcount, the TS, the umode, and all the USER information. + + The format for a full NICK line is: + NICK : + + The umode is a + followed by any applying usermodes. + + The format for a nick-change NICK line is: + : NICK : + + . When a NICK is received from a TS server, that conflicts with an + existing nick: + + if the userhosts differ or one is not known: + * if the timestamps are equal, kill ours and the old one if it + was a nick change + * if the incoming timestamp is older than ours, kill ours and + propagate the new one + * if the incoming timestamp is younger, ignore the line, but kill + the old nick if it was a nick change + + if the userhosts are the same: + * if the timestamps are equal, kill ours and the old one if it + was a nick change + * if the incoming timestamp is younger, kill ours and propagate + the new one + * if the incoming timestamp is older, ignore the line but kill + the old nick if it was a nick change + + . When a NICK is received from a non-TS server that conflicts with + an existing nick, kill both. + + . Do not send "Fake Prefix" kills in response to lines coming from TS + servers; the sanitization works anyway, and this allows the "newer + nick overruled" case to work. + + Explanations: + + The modified nick-introduction syntax allows for a slightly shorter + connect-burst, and most importantly lets the server compare + user@host's when determining which nick to kill: if the user@host + is the same, then the older nick must be killed rather than the + newer. + + When talking to a non-TS server, we need to behave exactly like one + because it expects us to. When talkign to a TS server, we don't kill + the nicks it's introducing, as we know it'll be smart enough to do it + itself when seeing our own introduced nick. + + When we see a nick arriving from a non-TS server, it won't have a TS, + but it's safe enough to give it the current time rather than keeping + it 0; such TS's won't be the same all across the network (as long as + there is more than one TS zone), and when there's a collision, the TS + used will be the one in the zone the collision occurs in. + + Also, it is important to note that by the time a server sees (and + chooses to ignore) a nick introduction, the introducing server has + also had the time to put umode changes for that nick on its queue, so + we must ignore them too... so we need to ignore fake-prefix lines + rather than sending kills for them. This is safe enough, as the rest + of the protocol ensures that they'll get killed anyway (and the + Undernet does it too, so it's been more than enough tested). Just for + an extra bit of compatibility, we still kill fake prefixes coming from + non-TS servers. + + This part of the TS protocol is almost exactly the same as the + Undernet's .anc (anti-nick-collide) patches, except that Undernet + servers don't add usermodes to the NICK line. + + + TimeStamped channel descriptions (avoiding hacked ops and desynchs): + ==================================================================== + + . For each channel, keep a timestamp, set to the current time when the + channel is created by a client on the local server, or to the received + value if the channel has been propagated from a TS server, or to 0 + otherwise. This value will have the semantics of "the time of creation + of the current ops on the channel", and 0 will mean that the channel + is in non-TS mode. + + A new server protocol command is introduced, SJOIN, which introduces + a full channel description: a timestamp, all the modes (except bans), + and the list of channel members with their ops and voices. This + command will be used instead of JOIN and of (most) MODEs both in + connect bursts and when propagating channel creations among TS + servers. SJOIN will never be accepted from or sent to users. + + The syntax for the command is: + + SJOIN # :[@][+] ... [@][+] + + The fields have the following meanings: + + * is the timestamp for the channel + + * is the list of global channel modes, starting with a + + and a letter for each of the active modes (spmntkil), followed + by an argument for +l if there is a limit, and an argument for + +k if there's a key (in the same order they were mentioned in + the string of letters). + + A channel with no modes will have a "+" in that field. + + A special value of "0" means that the server does not specify the + modes, and will be used when more than one SJOIN line is needed + to completely describe a channel, or when propagating a SJOIN + the modes of which were rejected. + + * Each nick is preceded by a "@" if the user has ops, and a "+" if + the user has a voice. For mode +ov, both flags are used. + + SJOINs will be propagated (when appropriate) to neighboring TS + servers, and converted to JOINs and MODEs for neighboring non-TS + servers. + + To propagate channels for which not all users fit in one + SJOIN line, several SJOINs will be sent consecutively, only the first + one including actual information in the field. + + An extra ad-hoc restriction is imposed on SJOIN messages, to simplify + processing: if a channel has ops, then the first of the first + SJOIN sent to propagate that channel must be one of the ops. + + Servers will never attempt to reconstruct a SJOIN from JOIN/MODE + information being received at the moment from other servers. + + . For each user on a channel, keep an extra flag (like ops and voice) + that is set when the user has received channel ops from another + server (in a SJOIN channel description), which we rejected (ignored). + Mode changes (but NOT kicks) coming from a TS server and from someone + with this flag set will be ignored. The flag will be reset when the + user gets ops from another user or server. + + . On deops done by non-local users, coming from TS servers, on channels + with a non-zero TS, do not check that the user has ops but check that + their 'deopped' flag is not set. For kicks coming from a TS server, do + not check either. This will avoid desynchs, and 'bad' modechanges are + avoided anyway. Other mode changes will still only be taken into + account and propagated when done by users that are seen as having ops. + + . When a MODE change that ops someone is received from a server for a + channel, that channel's TS is set to 0, and the mode change is + propagated. + + . When a SJOIN is received for a channel, deal with it in this way: + * received-TS = 0: + + if we have ops or the SJOIN doesn't op anyone, SJOIN propagated + with our own TS. + + otherwise, TS set to 0 and SJOIN propagated with 0. + * received-TS > 0, own-TS = 0: + + if the SJOIN ops someone or we don't have ops, set our TS to the + received TS and propagate. + + otherwise, propagate with TS = 0. + * received-TS = own-TS: propagate. + * received-TS < own-TS: + + if the SJOIN ops someone, remove *all* modes (except bans) from + the channel and propagate these mode changes to all neighboring + non-TS servers, and copy the received TS and propagate the SJOIN. + + if the SJOIN does not op anyone and we have ops, propagate + with our own TS. + + otherwise, copy the received TS and propagate the SJOIN. + * received-TS > own-TS: + + if the SJOIN does not introduce any ops, process and propagate + with our own TS. + + if we have ops: for each person the mode change would op, set the + 'deopped' flag; process all the JOINs ignoring the '@' and '+' + flags; propagate without the flags and with our TS. + + if we don't have ops: set our TS to the received one, propagate + with the flags. + + + Explanations: + + This part of the protocol is the one that is most different (and + incompatible) with the Undernet's: we never timestamp MODE changes, + but instead we introduce the concept of time-stamped channel + descriptions. This way each server can determine, based on its state + and the received description, what the correct modes for a channel + are, and deop its own users if necessary. With this protocol, there is + *never* the need to reverse and bounce back a mode change. This is + both faster and more bandwith-effective. + + The end goal is to have a protocol will eventually protect channels + against hacked ops, while minimizing the impact on a mixed-server net. + In order to do this, whenever there is a conflict between a TS server + and a non-TS one, the non-TS one's idea of the whole situation + prevails. This means that channels will only have a TS when they have + been created on a TS-aware server, and will lose it whenever a server + op comes from a non-TS server. Also, at most one 'zone' will have a TS + for any given channel at any given time, ensuring that there won't be + any deops when zones are merged. However, when TS zones are merged, if + the side that has a TS also has ops, then the TS is kept across the + whole new zone. Effective protection will only be ensured once all + servers run TS patches and channels have been re-created, as there is + no way servers can assign a TS to a channel they are not creating + (like they do with nicks) without having unwanted deops later. + + The visible effects of this timestamped channel-description protocol + are that when a split rejoins, and one side has hacked ops, the other + side doesn't see any server mode changes (just like with Undernet's + TS), but the side that has hacked ops sees: + + * first the first server on the other side deopping and devoicing + everyone, and fixing the +spmntkli modes + * then other users joining, and getting server ops and voices + + The less obvious part of this protocol is its behavior in the case + that the younger side of a rejoin has servers that are lagged with + each other. In such a situation, a SJOIN that clears all modes and + sets the legitimate ones is being propagated from one server, and + lagged illegitimate mode changes and kicks are being propagated in the + opposite direction. In this case, a kick done by someone who is being + deopped by the SJOIN must be taken into account to keep the name list + in sync (and since it can only be kicking someone who also was on the + younger side), while a deop does not matter (and will be ignored by + the first server on the other side), and an opping *needs* to be + discareded to avoid hacked ops. + + The main property of timestamped channel descriptions that makes them + a very stable protocol even with lag and splits, is that they leave a + server in the same final state, independently of the order in which + channel descriptions coming from different servers are received. Even + when SJOINs and MODEs for the same channel are being propagated in + different direction because of several splits rejoining, the final + state will be the same, independently of the exact order in which each + server received the SJOINs, and will be the same across all the + servers in the same zone. + + diff -c -r -N irc2.8.21+CSr15/common/parse.c irc2.8.21+CSr16/common/parse.c *** irc2.8.21+CSr15/common/parse.c Fri Oct 20 16:01:12 1995 --- irc2.8.21+CSr16/common/parse.c Mon Dec 18 23:02:33 1995 *************** *** 487,552 **** aClient *cptr, *sptr; char *cmd; { ! sendto_ops("Message from %s[%s] != %s", sptr->name, ! sptr->from->name, get_client_name(cptr, TRUE)); if (IsServer(sptr) || IsMe(sptr)) { sendto_ops("Dropping link for fake direction: %s", cptr->name); return exit_client(cptr, cptr, &me, "Fake Direction"); } if (IsServer(cptr)) { ! sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s] != %s)", ! me.name, sptr->name, me.name, ! sptr->name, sptr->from->name, ! get_client_name(cptr, TRUE)); ! sptr->flags |= FLAGS_KILLED; ! return exit_client(cptr, sptr, &me, "Fake Prefix"); } /* Fake prefix came from a client of mine...something is screwed with it, so we can exit this one */ - return exit_client(cptr, cptr, &me, "Fake prefix"); - } - - static int av_cancel_clients(cptr, sptr, cmd) - aClient *cptr, *sptr; - char *cmd; - { - /* - * kill all possible points that are causing confusion here, - * I'm not sure I've got this all right... - * - avalon - * No, i don't think you do - * - comstud - */ - sendto_ops("Message (%s) for %s[%s!%s@%s] from %s", cmd, - sptr->name, sptr->from->name, sptr->from->username, - sptr->from->sockhost, get_client_name(cptr, TRUE)); - /* - * Incorrect prefix for a server from some connection. If it is a - * client trying to be annoying, just QUIT them, if it is a server - * then the same deal. - */ - if (IsServer(sptr) || IsMe(sptr)) - { - sendto_ops("Fake Direction: Not dropping: %s", cptr->name); - return exit_client(cptr, cptr, &me, "Fake Direction"); - } - /* - * Ok, someone is trying to impose as a client and things are - * confused. If we got the wrong prefix from a server, send out a - * kill, else just exit the lame client. - */ - if (IsServer(cptr)) - { - sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s] != %s)", - me.name, sptr->name, me.name, - sptr->name, sptr->from->name, - get_client_name(cptr, TRUE)); - sptr->flags |= FLAGS_KILLED; - return exit_client(cptr, sptr, &me, "Fake Prefix"); - } return exit_client(cptr, cptr, &me, "Fake prefix"); } --- 487,533 ---- aClient *cptr, *sptr; char *cmd; { ! if (IsServer(sptr) || IsMe(sptr) || (IsServer(cptr) && ! !DoesTS(cptr))) ! sendto_ops("Message from %s[%s] != %s", sptr->name, ! sptr->from->name, get_client_name(cptr, TRUE)); if (IsServer(sptr) || IsMe(sptr)) { sendto_ops("Dropping link for fake direction: %s", cptr->name); return exit_client(cptr, cptr, &me, "Fake Direction"); } + /* + ** with TS, fake prefixes are a common thing, during the + ** connect burst when there's a nick collision, and they + ** must be ignored rather than killed because one of the + ** two is surviving.. so we don't bother sending them to + ** all ops everytime, as this could send 'private' stuff + ** from lagged clients. we do send the ones that cause + ** servers to be dropped though, as well as the ones from + ** non-TS servers -orabidoo + */ if (IsServer(cptr)) { ! /* ! ** If the fake prefix from a client is coming from a TS server, ! ** discard it silently -orabidoo ! */ ! if (DoesTS(cptr)) ! return 0; ! else ! { ! sendto_serv_butone(NULL, ! ":%s KILL %s :%s (%s[%s] != %s)", ! me.name, sptr->name, me.name, ! sptr->name, sptr->from->name, ! get_client_name(cptr, TRUE)); ! sptr->flags |= FLAGS_KILLED; ! return exit_client(cptr, sptr, &me, "Fake Prefix"); ! } } /* Fake prefix came from a client of mine...something is screwed with it, so we can exit this one */ return exit_client(cptr, cptr, &me, "Fake prefix"); } diff -c -r -N irc2.8.21+CSr15/common/send.c irc2.8.21+CSr16/common/send.c *** irc2.8.21+CSr15/common/send.c Fri Oct 20 16:01:12 1995 --- irc2.8.21+CSr16/common/send.c Mon Dec 18 23:37:00 1995 *************** *** 455,460 **** --- 455,532 ---- } /* + * sendto_TS_server_butone + * + * Send a message to all connected TS servers except the 'one', if ts==1, + * and to all connected non-TS servers except the 'one', if ts==0. + */ + # ifndef USE_VARARGS + /*VARARGS*/ + void sendto_TS_serv_butone(ts, one, pattern, p1, p2, p3, p4, p5, p6, p7, p8) + int ts; + aClient *one; + char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8; + { + # else + void sendto_TS_serv_butone(ts, one, pattern, va_alist) + int ts; + aClient *one; + char *pattern; + va_dcl + { + va_list vl; + # endif + Reg1 int i; + Reg2 aClient *cptr; + #ifdef DOG3 + register int j,k=0; + fdlist send_fdlist; + #endif + + # ifdef USE_VARARGS + va_start(vl); + # endif + + # ifdef NPATH + check_command((long)2, pattern, p1, p2, p3); + # endif + + #ifdef DOG3 + for (i=serv_fdlist.entry[j=1];j<=serv_fdlist.last_entry; + i=serv_fdlist.entry[++j]) + #else + for (i = 0; i <= highest_fd; i++) + #endif + { + if (!(cptr = local[i]) || (one && cptr == one->from)) + continue; + #ifdef DOG3 + if ((DoesTS(cptr) != 0) == (ts != 0)) + #else + if (IsServer(cptr) && (DoesTS(cptr) != 0) == (ts != 0)) + #endif + # ifdef USE_VARARGS + sendto_one(cptr, pattern, vl); + } + va_end(vl); + # else + #ifdef DOG3 + send_fdlist.entry[++k] = i; + #else + sendto_one(cptr, pattern, p1, p2, p3, p4, + p5, p6, p7, p8); + #endif /* DOG3 */ + } + #ifdef DOG3 + send_fdlist.last_entry = k; + if (k) + sendto_fdlist(&send_fdlist,pattern,p1,p2,p3,p4,p5,p6,p7,p8); + #endif /* DOG3 */ + # endif + return; + } + + /* * sendto_common_channels() * * Sends a message to all people (inclusing user) on local server who are *************** *** 640,645 **** --- 712,810 ---- if (cptr == from) #else if ((cptr == from) || !IsServer(cptr)) + #endif + continue; + #ifdef DOG3 + if (!BadPtr(mask) && + #else + if (!BadPtr(mask) && IsServer(cptr) && + #endif + matches(mask, cptr->name)) + continue; + #ifdef USE_VARARGS + sendto_one(cptr, format, vl); + } + va_end(vl); + #else + #ifdef DOG3 + send_fdlist.entry[++k] = i; + #else + sendto_one(cptr, format, p1, p2, p3, p4, p5, p6, p7, p8, p9); + #endif + } + #ifdef DOG3 + send_fdlist.last_entry=k; + if (k) + sendto_fdlist(&send_fdlist,format,p1,p2,p3,p4,p5,p6,p7,p8,p9); + #endif /* DOG3 */ + #endif + } + + /* + * sendto_match_TS_servs + * + * if ts==0, send to all non-TS servers matching the mask + * if ts==1, send to all TS servers matching the mask + * (or to all if no mask) + */ + #ifndef USE_VARARGS + /*VARARGS*/ + void sendto_match_TS_servs(ts, chptr, from, format, + p1,p2,p3,p4,p5,p6,p7,p8,p9) + int ts; + aChannel *chptr; + aClient *from; + char *format, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9; + { + #else + void sendto_match_TS_servs(ts, chptr, from, format, va_alist) + int ts; + aChannel *chptr; + aClient *from; + char *format; + va_dcl + { + va_list vl; + #endif + Reg1 int i; + Reg2 aClient *cptr; + char *mask; + #ifdef DOG3 + register int j,k=0; + fdlist send_fdlist; + #endif + + #ifdef USE_VARARGS + va_start(vl); + #endif + + # ifdef NPATH + check_command((long)3, format, p1, p2, p3); + # endif + if (chptr) + { + if (*chptr->chname == '&') + return; + if (mask = (char *)rindex(chptr->chname, ':')) + mask++; + } + else + mask = (char *)NULL; + + #ifdef DOG3 + for (i=serv_fdlist.entry[j=1];j<=serv_fdlist.last_entry; + i=serv_fdlist.entry[++j]) + #else + for (i = 0; i <= highest_fd; i++) + #endif + { + if (!(cptr = local[i])) + continue; + #ifdef DOG3 + if ((cptr == from) || (DoesTS(cptr) != 0) != (ts != 0)) + #else + if ((cptr == from) || !IsServer(cptr) || + (DoesTS(cptr) != 0) != (ts != 0)) #endif continue; #ifdef DOG3 diff -c -r -N irc2.8.21+CSr15/include/comstud.h irc2.8.21+CSr16/include/comstud.h *** irc2.8.21+CSr15/include/comstud.h Sun Nov 12 17:16:42 1995 --- irc2.8.21+CSr16/include/comstud.h Tue Dec 19 21:06:18 1995 *************** *** 1,6 **** --- 1,15 ---- #ifndef COMSTUD_H #define COMSTUD_H + /* USE_DICH_CONF - define this to try a new code for K: line matching + - Note: This is a lot cleaner than Roy's kline + patches...as far as CPU usage...someone want to + test it? =) + - Also, this was written by Philippe Levan, not me =) + */ + + #define USE_DICH_CONF + /* MAXBUFFERS - make receive socket buffers the maximum size they can be...up to 64K NOTE: send buffers will remain at 8K as bad things will happen if *************** *** 194,200 **** want them logged */ ! #define FNAME_FAILED_OPER "/home/irc/irc2.8.21+CSr15/lib/logs/failed.log" /* CLIENT_NOTICES - define this if you wish to see client connecting and exiting notices via /umode +c --- 203,209 ---- want them logged */ ! #define FNAME_FAILED_OPER "/home/irc/irc2.8.21+CSr16/lib/logs/failed.log" /* CLIENT_NOTICES - define this if you wish to see client connecting and exiting notices via /umode +c *************** *** 278,284 **** and you wish to log clones */ ! #define FNAME_CLONELOG "/home/irc/irc2.8.21+CSr15/logs/clones.log" /* DEFAULT_IDLELIMIT - if you have CHECK_IDLE defined above, this value is the default # a client --- 287,293 ---- and you wish to log clones */ ! #define FNAME_CLONELOG "/home/irc/irc2.8.21+CSr16/lib/logs/clones.log" /* DEFAULT_IDLELIMIT - if you have CHECK_IDLE defined above, this value is the default # a client *************** *** 350,358 **** #define CLONE_TIME 30 /* END OF FILE */ - - - #endif /* COMSTUD_H */ --- 359,364 ---- diff -c -r -N irc2.8.21+CSr15/include/config.h irc2.8.21+CSr16/include/config.h *** irc2.8.21+CSr15/include/config.h Sun Nov 12 16:55:16 1995 --- irc2.8.21+CSr16/include/config.h Tue Dec 19 21:08:38 1995 *************** *** 107,114 **** * these are only the recommened names and paths. Change as needed. * You must define these to something, even if you don't really want them. */ ! #define DPATH "/home/irc/irc2.8.21+CSr15/lib" /* dir where all ircd stuff is */ ! #define SPATH "/home/irc/irc2.8.21+CSr15/lib/ircd" #define CPATH "ircd.conf" /* server configuration file */ #define MPATH "ircd.motd" /* server MOTD file */ #define LPATH "ircd.log" /* Where the debug file lives, if DEBUGMODE */ --- 107,114 ---- * these are only the recommened names and paths. Change as needed. * You must define these to something, even if you don't really want them. */ ! #define DPATH "/home/irc/irc2.8.21+CSr16/lib" /* dir where all ircd stuff is */ ! #define SPATH "/home/irc/irc2.8.21+CSr16/lib/ircd" #define CPATH "ircd.conf" /* server configuration file */ #define MPATH "ircd.motd" /* server MOTD file */ #define LPATH "ircd.log" /* Where the debug file lives, if DEBUGMODE */ *************** *** 122,129 **** * successful use of /oper. These are either full paths or files within DPATH. */ ! #define FNAME_USERLOG "/home/irc/irc2.8.21+CSr15/logs/users.log" /* */ ! #define FNAME_OPERLOG "/home/irc/irc2.8.21+CSr15/logs/opers.log" /* */ /* CHROOTDIR * --- 122,129 ---- * successful use of /oper. These are either full paths or files within DPATH. */ ! #define FNAME_USERLOG "/home/irc/irc2.8.21+CSr16/logs/users.log" /* */ ! #define FNAME_OPERLOG "/home/irc/irc2.8.21+CSr16/logs/opers.log" /* */ /* CHROOTDIR * *************** *** 324,330 **** /* * Max amount of internal send buffering when socket is stuck (bytes) */ ! #define MAXSENDQLENGTH 1500000 /* Recommended value: 100000 for leaves */ /* 700000 for backbones */ /* * BUFFERPOOL is the maximum size of the total of all sendq's. --- 324,330 ---- /* * Max amount of internal send buffering when socket is stuck (bytes) */ ! #define MAXSENDQLENGTH 3000000 /* Recommended value: 100000 for leaves */ /* 700000 for backbones */ /* * BUFFERPOOL is the maximum size of the total of all sendq's. diff -c -r -N irc2.8.21+CSr15/include/dog3.h irc2.8.21+CSr16/include/dog3.h *** irc2.8.21+CSr15/include/dog3.h Fri Oct 20 16:01:12 1995 --- irc2.8.21+CSr16/include/dog3.h Tue Dec 19 21:07:51 1995 *************** *** 6,12 **** #endif #define DEFAULT_LOADCFREQ 5 ! #define DEFAULT_LOADRECV 35 #define FDLISTCHKFREQ 2 #endif --- 6,12 ---- #endif #define DEFAULT_LOADCFREQ 5 ! #define DEFAULT_LOADRECV 110 #define FDLISTCHKFREQ 2 #endif diff -c -r -N irc2.8.21+CSr15/include/h.h irc2.8.21+CSr16/include/h.h *** irc2.8.21+CSr15/include/h.h Fri Oct 20 16:01:12 1995 --- irc2.8.21+CSr16/include/h.h Mon Dec 18 21:02:00 1995 *************** *** 148,158 **** --- 148,162 ---- /*VARARGS2*/ extern void sendto_serv_butone(); /*VARARGS2*/ + extern void sendto_TS_serv_butone(); + /*VARARGS2*/ extern void sendto_common_channels(); /*VARARGS3*/ extern void sendto_channel_butserv(); /*VARARGS3*/ extern void sendto_match_servs(); + /*VARARGS3*/ + extern void sendto_match_TS_servs(); /*VARARGS5*/ extern void sendto_match_butone(); /*VARARGS3*/ *************** *** 190,196 **** extern int m_names PROTO((aClient *, aClient *, int, char **)); extern int m_server_estab PROTO((aClient *)); extern void send_umode PROTO((aClient *, aClient *, int, int, char *)); ! extern void send_umode_out PROTO((aClient*, aClient *, int)); #endif extern void free_client PROTO((aClient *)); --- 194,200 ---- extern int m_names PROTO((aClient *, aClient *, int, char **)); extern int m_server_estab PROTO((aClient *)); extern void send_umode PROTO((aClient *, aClient *, int, int, char *)); ! extern void send_umode_out PROTO((aClient*, aClient *, int, int)); #endif extern void free_client PROTO((aClient *)); diff -c -r -N irc2.8.21+CSr15/include/msg.h irc2.8.21+CSr16/include/msg.h *** irc2.8.21+CSr15/include/msg.h Fri Oct 20 16:01:12 1995 --- irc2.8.21+CSr16/include/msg.h Mon Dec 18 21:46:23 1995 *************** *** 79,84 **** --- 79,89 ---- #define MSG_REHASH "REHASH" /* REHA */ #define MSG_RESTART "RESTART" /* REST */ #define MSG_CLOSE "CLOSE" /* CLOS */ + #define MSG_SVINFO "SVINFO" /* SVINFO */ + #define MSG_SJOIN "SJOIN" /* SJOIN */ + #ifdef TSDEBUG + #define MSG_TS "TS" /* TS */ + #endif #define MSG_DIE "DIE" #define MSG_HASH "HSAH" /* HASH */ #define MSG_DNS "DNS" /* DNS -> DNSS */ *************** *** 110,117 **** extern int m_time(), m_names(), m_admin(); extern int m_lusers(), m_umode(), m_note(), m_close(); extern int m_motd(), m_whowas(); ! extern int m_service(), m_userhost(), m_ison(); extern int m_service(), m_servset(), m_servlist(), m_squery(); #if defined(OPER_REHASH) || defined(LOCOP_REHASH) extern int m_rehash(); #endif --- 115,125 ---- extern int m_time(), m_names(), m_admin(); extern int m_lusers(), m_umode(), m_note(), m_close(); extern int m_motd(), m_whowas(); ! extern int m_service(), m_userhost(), m_ison(), m_svinfo(), m_sjoin(); extern int m_service(), m_servset(), m_servlist(), m_squery(); + #ifdef TSDEBUG + extern int m_ts(); + #endif #if defined(OPER_REHASH) || defined(LOCOP_REHASH) extern int m_rehash(); #endif *************** *** 169,174 **** --- 177,187 ---- { MSG_INFO, m_info, 0, MAXPARA, 1 ,0L }, { MSG_MOTD, m_motd, 0, MAXPARA, 1 ,0L }, { MSG_CLOSE, m_close, 0, MAXPARA, 1 ,0L }, + { MSG_SVINFO, m_svinfo, 0, MAXPARA, 1, 0L }, + { MSG_SJOIN, m_sjoin, 0, MAXPARA, 1, 0L }, + #ifdef TSDEBUG + { MSG_TS, m_ts, 0, MAXPARA, 1, 0L }, + #endif #ifdef IDLE_CHECK { MSG_IDLE, m_idle, 0, MAXPARA, 1 ,0L }, #endif diff -c -r -N irc2.8.21+CSr15/include/patchlevel.h irc2.8.21+CSr16/include/patchlevel.h *** irc2.8.21+CSr15/include/patchlevel.h Sun Nov 12 16:55:23 1995 --- irc2.8.21+CSr16/include/patchlevel.h Tue Dec 19 21:05:30 1995 *************** *** 17,21 **** */ #ifndef PATCHLEVEL ! #define PATCHLEVEL "2.8.21+CSr15" #endif --- 17,21 ---- */ #ifndef PATCHLEVEL ! #define PATCHLEVEL "2.8.21+CSr16" #endif diff -c -r -N irc2.8.21+CSr15/include/setup.h irc2.8.21+CSr16/include/setup.h *** irc2.8.21+CSr15/include/setup.h Fri Oct 20 16:01:12 1995 --- irc2.8.21+CSr16/include/setup.h Tue Dec 19 18:30:26 1995 *************** *** 5,11 **** #define STRINGH #define STRINGSH #define STDLIBH ! #define STDDEFH #define SYSSYSLOGH #undef NOINDEX #undef NEED_STRERROR --- 5,11 ---- #define STRINGH #define STRINGSH #define STDLIBH ! #undef STDDEFH #define SYSSYSLOGH #undef NOINDEX #undef NEED_STRERROR diff -c -r -N irc2.8.21+CSr15/include/struct.h irc2.8.21+CSr16/include/struct.h *** irc2.8.21+CSr15/include/struct.h Fri Oct 20 16:01:12 1995 --- irc2.8.21+CSr16/include/struct.h Mon Dec 18 23:49:22 1995 *************** *** 30,35 **** --- 30,38 ---- #ifdef STDDEFH # include #endif + #ifdef ORATIMING + #include + #endif #ifdef USE_SYSLOG # include *************** *** 48,53 **** --- 51,57 ---- typedef struct Server aServer; typedef struct SLink Link; typedef struct SMode Mode; + typedef long ts_val; typedef struct CloneItem aClone; *************** *** 336,346 **** --- 340,352 ---- time_t lasttime; /* ...should be only LOCAL clients? --msa */ time_t firsttime; /* time client was created */ time_t since; /* last time we parsed something */ + ts_val tsinfo; /* TS on the nick, SVINFO on servers */ long flags; /* client flags */ aClient *from; /* == self, if Local Client, *NEVER* NULL! */ int fd; /* >= 0, for local clients */ int hopcount; /* number of servers to this 0 = local */ short status; /* Client type */ + char nicksent; char name[HOSTLEN+1]; /* Unique name of the client, nick or host */ char username[USERLEN+1]; /* username here now for auth stuff */ char info[REALLEN+1]; /* Free form additional client information */ *************** *** 473,481 **** --- 479,494 ---- Link *members; Link *invites; Link *banlist; + ts_val channelts; char chname[1]; }; + #define TS_CURRENT 1 /* current TS protocol version */ + #define TS_MIN 1 /* minimum supported TS protocol version */ + #define TS_LEAVEIT 0x10000000 + #define TS_DOESTS 0x20000000 + #define DoesTS(x) ((x)->tsinfo == TS_DOESTS) + /* ** Channel Related macros follow */ *************** *** 484,505 **** #define CHFL_CHANOP 0x0001 /* Channel operator */ #define CHFL_VOICE 0x0002 /* the power to speak */ ! #define CHFL_BAN 0x0004 /* ban channel flag */ /* Channel Visibility macros */ #define MODE_CHANOP CHFL_CHANOP #define MODE_VOICE CHFL_VOICE ! #define MODE_PRIVATE 0x0004 ! #define MODE_SECRET 0x0008 ! #define MODE_MODERATED 0x0010 ! #define MODE_TOPICLIMIT 0x0020 ! #define MODE_INVITEONLY 0x0040 ! #define MODE_NOPRIVMSGS 0x0080 ! #define MODE_KEY 0x0100 ! #define MODE_BAN 0x0200 ! #define MODE_LIMIT 0x0400 ! #define MODE_FLAGS 0x07ff /* * mode flags which take another parameter (With PARAmeterS) */ --- 497,520 ---- #define CHFL_CHANOP 0x0001 /* Channel operator */ #define CHFL_VOICE 0x0002 /* the power to speak */ ! #define CHFL_DEOPPED 0x0004 /* deopped by us, modes need to be bounced */ ! #define CHFL_BAN 0x0008 /* ban channel flag */ /* Channel Visibility macros */ #define MODE_CHANOP CHFL_CHANOP #define MODE_VOICE CHFL_VOICE ! #define MODE_DEOPPED CHFL_DEOPPED ! #define MODE_PRIVATE 0x0008 ! #define MODE_SECRET 0x0010 ! #define MODE_MODERATED 0x0020 ! #define MODE_TOPICLIMIT 0x0040 ! #define MODE_INVITEONLY 0x0080 ! #define MODE_NOPRIVMSGS 0x0100 ! #define MODE_KEY 0x0200 ! #define MODE_BAN 0x0400 ! #define MODE_LIMIT 0x0800 ! #define MODE_FLAGS 0x0fff /* * mode flags which take another parameter (With PARAmeterS) */ *************** *** 576,581 **** --- 591,615 ---- #define FLUSH_BUFFER -2 #define UTMP "/etc/utmp" #define COMMA "," + + #ifdef ORATIMING + /* Timing stuff (for performance measurements): compile with -DORATIMING + and put a TMRESET where you want the counter of time spent set to 0, + a TMPRINT where you want the accumulated results, and TMYES/TMNO pairs + around the parts you want timed -orabidoo + */ + extern struct timeval tsdnow, tsdthen; + extern unsigned long tsdms; + #define TMRESET tsdms=0; + #define TMYES gettimeofday(&tsdthen, NULL); + #define TMNO gettimeofday(&tsdnow, NULL); if (tsdnow.tv_sec!=tsdthen.tv_sec) tsdms+=1000000*(tsdnow.tv_sec-tsdthen.tv_sec); tsdms+=tsdnow.tv_usec; tsdms-=tsdthen.tv_usec; + #define TMPRINT sendto_ops("Time spent: %ld ms", tsdms); + #else + #define TMRESET + #define TMYES + #define TMNO + #define TMPRINT + #endif /* IRC client structures */ diff -c -r -N irc2.8.21+CSr15/ircd/Makefile irc2.8.21+CSr16/ircd/Makefile *** irc2.8.21+CSr15/ircd/Makefile Fri Oct 20 16:01:13 1995 --- irc2.8.21+CSr16/ircd/Makefile Tue Dec 19 18:59:03 1995 *************** *** 83,89 **** OBJS=channel.o class.o hash.o ircd.o list.o res.o s_auth.o s_bsd.o s_conf.o \ s_debug.o s_err.o s_misc.o s_numeric.o s_serv.o s_user.o whowas.o \ ! note.o clone.o fdlist.o $(RES) $(COMMONOBJS) SRC=$(OBJS:%.o=%.c) --- 83,89 ---- OBJS=channel.o class.o hash.o ircd.o list.o res.o s_auth.o s_bsd.o s_conf.o \ s_debug.o s_err.o s_misc.o s_numeric.o s_serv.o s_user.o whowas.o \ ! note.o clone.o fdlist.o dich_conf.o $(RES) $(COMMONOBJS) SRC=$(OBJS:%.o=%.c) *************** *** 185,191 **** $(CC) $(CFLAGS) -c s_auth.c s_conf.o: s_conf.c ../include/struct.h ../include/config.h ../include/sys.h \ ! ../include/common.h ../include/numeric.h ../include/dbuf.h $(CC) $(CFLAGS) -c s_conf.c s_debug.o: ../include/config.h ../include/struct.h ../include/common.h \ --- 185,192 ---- $(CC) $(CFLAGS) -c s_auth.c s_conf.o: s_conf.c ../include/struct.h ../include/config.h ../include/sys.h \ ! ../include/common.h ../include/numeric.h ../include/dbuf.h \ ! ../include/comstud.h $(CC) $(CFLAGS) -c s_conf.c s_debug.o: ../include/config.h ../include/struct.h ../include/common.h \ *************** *** 228,233 **** --- 229,238 ---- @/bin/rm -f hash.c @/bin/mv -f hash.c.old hash.c @touch hash.o + + dich_conf.o: dich_conf.h ../include/struct.h ../include/common.h \ + dich_conf.c + $(CC) $(CFLAGS) -c dich_conf.c # DO NOT DELETE THIS LINE -- make depend depends on it. diff -c -r -N irc2.8.21+CSr15/ircd/channel.c irc2.8.21+CSr16/ircd/channel.c *** irc2.8.21+CSr15/ircd/channel.c Fri Oct 20 16:01:13 1995 --- irc2.8.21+CSr16/ircd/channel.c Tue Dec 19 21:24:55 1995 *************** *** 59,64 **** --- 59,75 ---- void clean_channelname PROTO((char *)); void del_invite PROTO((aClient *, aChannel *)); + #ifdef ORATIMING + struct timeval tsdnow, tsdthen; + unsigned long tsdms; + #endif + + /* + ** number of seconds to add to all readings of time() when making TS's + ** -orabidoo + */ + ts_val timedelta = 0; + static char *PartFmt = ":%s PART %s"; /* * some buffers for rebuilding channel/nick lists with ,'s *************** *** 381,387 **** if (mine && tmp->flags & (lp->flags & MODE_FLAGS)) return 0; #endif ! tmp->flags |= lp->flags & MODE_FLAGS; } else { --- 392,400 ---- if (mine && tmp->flags & (lp->flags & MODE_FLAGS)) return 0; #endif ! tmp->flags |= lp->flags & MODE_FLAGS; ! if (lp->flags & MODE_CHANOP) ! tmp->flags &= ~MODE_DEOPPED; } else { *************** *** 389,399 **** if (mine && !(tmp->flags & (lp->flags & MODE_FLAGS))) return 0; #endif ! tmp->flags &= ~lp->flags & MODE_FLAGS; } return 1; } int is_chan_op(cptr, chptr) aClient *cptr; aChannel *chptr; --- 402,423 ---- if (mine && !(tmp->flags & (lp->flags & MODE_FLAGS))) return 0; #endif ! tmp->flags &= ~lp->flags & MODE_FLAGS; } return 1; } + static void set_deopped(lp, chptr) + Link *lp; + aChannel *chptr; + { + Reg1 Link *tmp; + + if ((tmp = find_user_link(chptr->members, lp->value.cptr))) + if ((tmp->flags & MODE_CHANOP) == 0) + tmp->flags |= MODE_DEOPPED; + } + int is_chan_op(cptr, chptr) aClient *cptr; aChannel *chptr; *************** *** 407,412 **** --- 431,449 ---- return 0; } + int is_deopped(cptr, chptr) + aClient *cptr; + aChannel *chptr; + { + Reg1 Link *lp; + + if (chptr) + if ((lp = find_user_link(chptr->members, cptr))) + return (lp->flags & CHFL_DEOPPED); + + return 0; + } + int has_voice(cptr, chptr) aClient *cptr; aChannel *chptr; *************** *** 552,577 **** *modebuf = *parabuf = '\0'; channel_modes(cptr, modebuf, parabuf, chptr); ! send_mode_list(cptr, chptr->chname, chptr->members, CHFL_CHANOP, 'o'); ! if (modebuf[1] || *parabuf) ! sendto_one(cptr, ":%s MODE %s %s %s", ! me.name, chptr->chname, modebuf, parabuf); ! *parabuf = '\0'; ! *modebuf = '+'; ! modebuf[1] = '\0'; ! send_mode_list(cptr, chptr->chname, chptr->banlist, CHFL_BAN, 'b'); ! if (modebuf[1] || *parabuf) ! sendto_one(cptr, ":%s MODE %s %s %s", ! me.name, chptr->chname, modebuf, parabuf); ! *parabuf = '\0'; ! *modebuf = '+'; ! modebuf[1] = '\0'; ! send_mode_list(cptr, chptr->chname, chptr->members, CHFL_VOICE, 'v'); ! if (modebuf[1] || *parabuf) ! sendto_one(cptr, ":%s MODE %s %s %s", ! me.name, chptr->chname, modebuf, parabuf); } /* --- 589,695 ---- *modebuf = *parabuf = '\0'; channel_modes(cptr, modebuf, parabuf, chptr); ! if (DoesTS(cptr)) ! { ! Link *l, *anop = NULL, *skip = NULL; ! int n = 0; ! char *t; ! ! if (*parabuf) ! strcat(parabuf, " "); ! sprintf(buf, ":%s SJOIN %ld %s %s %s:", me.name, ! chptr->channelts, chptr->chname, modebuf, parabuf); ! t = buf + strlen(buf); ! for (l = chptr->members; l && l->value.cptr; l = l->next) ! if (l->flags & MODE_CHANOP) ! { ! anop = l; ! break; ! } ! /* follow the channel, but doing anop first if it's defined ! ** -orabidoo ! */ ! l = NULL; ! for (;;) ! { ! if (anop) ! { ! l = skip = anop; ! anop = NULL; ! } ! else ! { ! if (l == NULL || l == skip) ! l = chptr->members; ! else ! l = l->next; ! if (l && l == skip) ! l = l->next; ! if (l == NULL) ! break; ! } ! if (l->flags & MODE_CHANOP) ! *t++ = '@'; ! if (l->flags & MODE_VOICE) ! *t++ = '+'; ! strcpy(t, l->value.cptr->name); ! t += strlen(t); ! *t++ = ' '; ! n++; ! if (t - buf > BUFSIZE - 80) ! { ! *t++ = '\0'; ! if (t[-1] == ' ') t[-1] = '\0'; ! sendto_one(cptr, "%s", buf); ! sprintf(buf, ":%s SJOIN %ld %s 0 :", ! me.name, chptr->channelts, ! chptr->chname); ! t = buf + strlen(buf); ! n = 0; ! } ! } ! if (n) ! { ! *t++ = '\0'; ! if (t[-1] == ' ') t[-1] = '\0'; ! sendto_one(cptr, "%s", buf); ! } ! *parabuf = '\0'; ! *modebuf = '+'; ! modebuf[1] = '\0'; ! send_mode_list(cptr, chptr->chname, chptr->banlist, CHFL_BAN, ! 'b'); ! if (modebuf[1] || *parabuf) ! sendto_one(cptr, ":%s MODE %s %s %s", ! me.name, chptr->chname, modebuf, parabuf); ! } ! else ! { ! send_mode_list(cptr, chptr->chname, chptr->members, ! CHFL_CHANOP, 'o'); ! if (modebuf[1] || *parabuf) ! sendto_one(cptr, ":%s MODE %s %s %s", ! me.name, chptr->chname, modebuf, parabuf); ! *parabuf = '\0'; ! *modebuf = '+'; ! modebuf[1] = '\0'; ! send_mode_list(cptr, chptr->chname, chptr->banlist, CHFL_BAN, ! 'b'); ! if (modebuf[1] || *parabuf) ! sendto_one(cptr, ":%s MODE %s %s %s", ! me.name, chptr->chname, modebuf, parabuf); ! ! *parabuf = '\0'; ! *modebuf = '+'; ! modebuf[1] = '\0'; ! send_mode_list(cptr, chptr->chname, chptr->members, CHFL_VOICE, ! 'v'); ! if (modebuf[1] || *parabuf) ! sendto_one(cptr, ":%s MODE %s %s %s", ! me.name, chptr->chname, modebuf, parabuf); ! } } /* *************** *** 623,658 **** mcount = set_mode(cptr, sptr, chptr, parc - 2, parv + 2, modebuf, parabuf); - if ((mcount < 0) && MyConnect(sptr) && !IsServer(sptr)) - { - sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), - me.name, parv[0], chptr->chname); - return 0; - } if (strlen(modebuf) > (size_t)1) ! { ! if ((IsServer(cptr) && !IsServer(sptr) && !chanop) || ! (mcount < 0)) { #ifndef DONT_SEND_FAKES #ifdef FK_USERMODES ! sendto_flagops(4,"Fake: %s MODE %s %s %s", ! parv[0], parv[1], modebuf, parabuf); #else ! sendto_ops("Fake: %s MODE %s %s %s", ! parv[0], parv[1], modebuf, parabuf); #endif #endif ! ircstp->is_fake++; ! } ! else ! sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s", parv[0], chptr->chname, modebuf, parabuf); ! sendto_match_servs(chptr, cptr, ":%s MODE %s %s %s", ! parv[0], chptr->chname, modebuf, parabuf); ! } return 0; } --- 741,780 ---- mcount = set_mode(cptr, sptr, chptr, parc - 2, parv + 2, modebuf, parabuf); if (strlen(modebuf) > (size_t)1) ! switch (mcount) { + case 0: + break; + case -1: + if (MyClient(sptr)) + sendto_one(sptr, + err_str(ERR_CHANOPRIVSNEEDED), + me.name, parv[0], chptr->chname); + else + { #ifndef DONT_SEND_FAKES #ifdef FK_USERMODES ! sendto_flagops(4,"Fake: %s MODE %s %s %s", ! parv[0], parv[1], modebuf, parabuf); #else ! sendto_ops("Fake: %s MODE %s %s %s", ! parv[0], parv[1], modebuf, parabuf); #endif #endif ! ircstp->is_fake++; ! } ! break; ! default: ! sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s", parv[0], chptr->chname, modebuf, parabuf); ! sendto_match_servs(chptr, cptr, ! ":%s MODE %s %s %s", ! parv[0], chptr->chname, ! modebuf, parabuf); ! } return 0; } *************** *** 672,678 **** MODE_PRIVATE, 'p', MODE_SECRET, 's', MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n', MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i', - MODE_VOICE, 'v', MODE_KEY, 'k', 0x0, 0x0 }; Reg1 Link *lp; --- 794,799 ---- *************** *** 680,686 **** Reg3 int *ip; u_int whatt = MODE_ADD; int limitset = 0, count = 0, chasing = 0; ! int nusers, ischop, new, len, keychange = 0, opcnt = 0; char fm = '\0'; aClient *who; Mode *mode, oldm; --- 801,808 ---- Reg3 int *ip; u_int whatt = MODE_ADD; int limitset = 0, count = 0, chasing = 0; ! int nusers, ischop, isok, isdeop, new, len; ! int keychange = 0, opcnt = 0; char fm = '\0'; aClient *who; Mode *mode, oldm; *************** *** 692,697 **** --- 814,822 ---- mode = &(chptr->mode); bcopy((char *)mode, (char *)&oldm, sizeof(Mode)); ischop = IsServer(sptr) || is_chan_op(sptr, chptr); + isdeop = !ischop && !IsServer(sptr) && is_deopped(sptr, chptr); + isok = ischop || (!isdeop && IsServer(cptr) && DoesTS(cptr) && + chptr->channelts); new = mode->mode; while (curr && *curr && count >= 0) *************** *** 733,743 **** ** just some extra messages if nick appeared more than ** once in the MODE message... --msa */ ! if (chasing && ischop) ! sendto_one(cptr, ":%s MODE %s %c%c %s", ! me.name, chptr->chname, ! whatt == MODE_ADD ? '+' : '-', ! *curr, who->name); if (who == cptr && whatt == MODE_ADD && *curr == 'o') break; --- 858,871 ---- ** just some extra messages if nick appeared more than ** once in the MODE message... --msa */ ! /* ! ** This is actually useless - if we notice a nick ! ** change it means the server the mode comes from ! ** dealt with the mode with the old nick, and already ! ** applied it, and the nick change must be coming ! ** from another server; besides, we don't want to ! ** be resetting the channel's TS -orabidoo ! */ if (who == cptr && whatt == MODE_ADD && *curr == 'o') break; *************** *** 870,875 **** --- 998,1004 ---- { limitset = 1; nusers = 0; + count++; break; } if (--parc > 0) *************** *** 931,936 **** --- 1060,1083 ---- whatt = 0; + /* if it's a non-deopped non-op on a TS channel from a TS + ** server, allow only deops and ignore everything else (to + ** avoid "i deop you you deop me"-type desynchs) -orabidoo + */ + if (!ischop && isok) + { + Reg1 int i; + Reg2 int j; + + new = oldm.mode; + for (i = 0, j = 0; i < opcnt; i++) + if (chops[i].flags == (MODE_CHANOP | MODE_DEL)) + chops[j++] = chops[i]; + else + count--; + opcnt = j; + } + for (ip = flags; *ip; ip += 2) if ((*ip & new) && !(*ip & oldm.mode)) { *************** *** 1074,1088 **** case MODE_CHANOP : case MODE_VOICE : /* pass fakes along? nawww */ ! if (ischop && change_chan_flag(lp, chptr, ! MyClient(sptr))) ! { ! *mbuf++ = c; ! (void)strcat(pbuf, cp); ! len += strlen(cp); ! (void)strcat(pbuf, " "); ! len++; ! } break; case MODE_BAN : if (ischop && ((whatt & MODE_ADD) && --- 1221,1246 ---- case MODE_CHANOP : case MODE_VOICE : /* pass fakes along? nawww */ ! /* uh-huh.. if they're fake, they'd go ! into a FAKE, not get sent along as ! a MODE -orabidoo ! */ ! if (IsServer(sptr) && c == 'o' && ! whatt == MODE_ADD) ! chptr->channelts = 0; ! if (c == 'o' && whatt == MODE_ADD && isdeop && ! !is_chan_op(lp->value.cptr, chptr)) ! set_deopped(lp, chptr); ! if ((ischop || (isok && c == 'o' && ! whatt == MODE_DEL)) && ! change_chan_flag(lp, chptr, MyClient(sptr))) ! { ! *mbuf++ = c; ! (void)strcat(pbuf, cp); ! len += strlen(cp); ! (void)strcat(pbuf, " "); ! len++; ! } break; case MODE_BAN : if (ischop && ((whatt & MODE_ADD) && *************** *** 1103,1109 **** *mbuf++ = '\0'; ! return ischop ? count : -count; } static int can_join(sptr, chptr, key) --- 1261,1279 ---- *mbuf++ = '\0'; ! /* returns: ! ** -1 = mode changes were generated but ignored, and a FAKE ! ** must be sent for remote clients and a CHANOPRIVSNEEDED ! ** for local ones ! ** 0 = ignore whatever was generated, do not propagate anything ! ** >0 = modes were accepted, propagate ! */ ! if (isok) ! return count; ! if (isdeop && !MyClient(sptr)) ! return 0; ! else ! return -1; } static int can_join(sptr, chptr, key) *************** *** 1435,1451 **** */ add_user_to_channel(chptr, sptr, flags); /* ** notify all other users on the new channel */ sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name); - sendto_match_servs(chptr, cptr, ":%s JOIN :%s", parv[0], name); if (MyClient(sptr)) { del_invite(sptr, chptr); if (flags == CHFL_CHANOP) ! sendto_match_servs(chptr, cptr, ":%s MODE %s +o %s", me.name, name, parv[0]); if (chptr->topic[0] != '\0') --- 1605,1636 ---- */ add_user_to_channel(chptr, sptr, flags); /* + ** Set timestamp if appropriate, and propagate + */ + if (MyClient(sptr) && flags) + { + chptr->channelts = time(NULL) + timedelta; + sendto_match_TS_servs(0, chptr, cptr, ":%s JOIN :%s", + parv[0], name); + sendto_match_TS_servs(1, chptr, cptr, + ":%s SJOIN %ld %s + :@%s", + me.name, chptr->channelts, name, + parv[0]); + } + else + sendto_match_servs(chptr, cptr, ":%s JOIN :%s", parv[0], + name); + /* ** notify all other users on the new channel */ sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name); if (MyClient(sptr)) { del_invite(sptr, chptr); if (flags == CHFL_CHANOP) ! sendto_match_TS_servs(0, chptr, cptr, ":%s MODE %s +o %s", me.name, name, parv[0]); if (chptr->topic[0] != '\0') *************** *** 1582,1588 **** } if (check_channelmask(sptr, cptr, name)) continue; ! if (!IsServer(sptr) && !is_chan_op(sptr, chptr)) { sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0], chptr->chname); --- 1767,1774 ---- } if (check_channelmask(sptr, cptr, name)) continue; ! if (!IsServer(sptr) && !is_chan_op(sptr, chptr) && ! (MyConnect(sptr) || !DoesTS(cptr) || !chptr->channelts)) { sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0], chptr->chname); *************** *** 1927,1933 **** hunt_server(cptr, sptr, ":%s NAMES %s %s", 2, parc, parv)) return 0; ! mlen = strlen(me.name) + 10; if (!BadPtr(para)) { --- 2113,2119 ---- hunt_server(cptr, sptr, ":%s NAMES %s %s", 2, parc, parv)) return 0; ! mlen = strlen(me.name) + NICKLEN + 7; if (!BadPtr(para)) { *************** *** 1989,1995 **** idx += strlen(c2ptr->name) + 1; flag = 1; (void)strcat(buf," "); ! if (mlen + idx + NICKLEN > BUFSIZE - 2) { sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); --- 2175,2181 ---- idx += strlen(c2ptr->name) + 1; flag = 1; (void)strcat(buf," "); ! if (mlen + idx + NICKLEN > BUFSIZE - 3) { sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf); *************** *** 2112,2114 **** --- 2298,2744 ---- return; } + + static void sjoin_sendit(cptr, sptr, chptr, from) + aClient *cptr; + aClient *sptr; + aChannel *chptr; + char *from; + { + sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s", from, + chptr->chname, modebuf, parabuf); + + sendto_match_TS_servs(0, chptr, cptr, ":%s MODE %s %s %s", + from, chptr->chname, modebuf, parabuf); + } + + /* + * m_sjoin + * parv[0] - sender + * parv[1] - TS + * parv[2] - channel + * parv[3] - modes + n arguments (key and/or limit) + * parv[4+n] - flags+nick list (all in one parameter) + + * + * process a SJOIN, taking the TS's into account to either ignore the + * incomign modes or undo the existing ones or merge them, and JOIN + * all the specified users while sending JOIN/MODEs to non-TS servers + * and to clients + */ + + int m_sjoin(cptr, sptr, parc, parv) + aClient *cptr; + aClient *sptr; + int parc; + char *parv[]; + { + aChannel *chptr; + aClient *acptr; + ts_val newts, oldts, tstosend; + static Mode mode, *oldmode; + Link *l; + int args = 0, haveops = 0, keepourmodes = 1, keepnewmodes = 1, + doesop = 0, what = 0, pargs = 0, *ip, fl, people = 0; + Reg1 char *s, *s0; + static char numeric[16], sjbuf[BUFSIZE]; + char *mbuf = modebuf, *t = sjbuf, *p; + + static int flags[] = { + MODE_PRIVATE, 'p', MODE_SECRET, 's', + MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n', + MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i', + 0x0, 0x0 }; + + if (check_registered(sptr) || IsClient(sptr) || parc < 5) + return 0; + if (!IsChannelName(parv[2]) || + check_channelmask(sptr, cptr, parv[2]) == -1) + return 0; + newts = atol(parv[1]); + bzero((char *)&mode, sizeof(mode)); + + s = parv[3]; + while (*s) + switch(*(s++)) + { + case 'i': + mode.mode |= MODE_INVITEONLY; + break; + case 'n': + mode.mode |= MODE_NOPRIVMSGS; + break; + case 'p': + mode.mode |= MODE_PRIVATE; + break; + case 's': + mode.mode |= MODE_SECRET; + break; + case 'm': + mode.mode |= MODE_MODERATED; + break; + case 't': + mode.mode |= MODE_TOPICLIMIT; + break; + case 'k': + strncpyzt(mode.key, parv[4+args], KEYLEN+1); + args++; + if (parc < 5+args) return 0; + break; + case 'l': + mode.limit = atoi(parv[4+args]); + args++; + if (parc < 5+args) return 0; + break; + } + + *parabuf = '\0'; + + chptr = get_channel(sptr, parv[2], CREATE); + oldts = chptr->channelts; + doesop = (parv[4+args][0] == '@' || parv[4+args][1] == '@'); + + for (l = chptr->members; l && l->value.cptr; l = l->next) + if (l->flags & MODE_CHANOP) + { + haveops++; + break; + } + + oldmode = &chptr->mode; + + if (newts == 0) + if (haveops || !doesop) + tstosend = oldts; + else + chptr->channelts = tstosend = 0; + else if (oldts == 0) + if (doesop || !haveops) + chptr->channelts = tstosend = newts; + else + tstosend = 0; + else if (newts == oldts) + tstosend = oldts; + else if (newts < oldts) + { + if (doesop) + keepourmodes = 0; + if (haveops && !doesop) + tstosend = oldts; + else + chptr->channelts = tstosend = newts; + } + else + { + if (haveops) + keepnewmodes = 0; + if (doesop && !haveops) + { + chptr->channelts = tstosend = newts; + if (MyConnect(sptr)) + sendto_ops("Hacked ops on opless channel: %s", + chptr->chname); + } + else + tstosend = oldts; + } + + if (!keepnewmodes) + mode = *oldmode; + else if (keepourmodes) + { + mode.mode |= oldmode->mode; + if (oldmode->limit > mode.limit) + mode.limit = oldmode->limit; + if (strcmp(mode.key, oldmode->key) < 0) + strcpy(mode.key, oldmode->key); + } + + for (ip = flags; *ip; ip += 2) + if ((*ip & mode.mode) && !(*ip & oldmode->mode)) + { + if (what != 1) + { + *mbuf++ = '+'; + what = 1; + } + *mbuf++ = *(ip+1); + } + for (ip = flags; *ip; ip += 2) + if ((*ip & oldmode->mode) && !(*ip & mode.mode)) + { + if (what != -1) + { + *mbuf++ = '-'; + what = -1; + } + *mbuf++ = *(ip+1); + } + if (oldmode->limit && !mode.limit) + { + if (what != -1) + { + *mbuf++ = '-'; + what = -1; + } + *mbuf++ = 'l'; + } + if (oldmode->key[0] && !mode.key[0]) + { + if (what != -1) + { + *mbuf++ = '-'; + what = -1; + } + *mbuf++ = 'k'; + strcat(parabuf, oldmode->key); + strcat(parabuf, " "); + pargs++; + } + if (mode.limit && oldmode->limit != mode.limit) + { + if (what != 1) + { + *mbuf++ = '+'; + what = 1; + } + *mbuf++ = 'l'; + (void)sprintf(numeric, "%-15d", mode.limit); + if ((s = index(numeric, ' '))) + *s = '\0'; + strcat(parabuf, numeric); + strcat(parabuf, " "); + pargs++; + } + if (mode.key[0] && strcmp(oldmode->key, mode.key)) + { + if (what != 1) + { + *mbuf++ = '+'; + what = 1; + } + *mbuf++ = 'k'; + strcat(parabuf, mode.key); + strcat(parabuf, " "); + pargs++; + } + + chptr->mode = mode; + + if (!keepourmodes) + { + what = 0; + for (l = chptr->members; l && l->value.cptr; l = l->next) + { + if (l->flags & MODE_CHANOP) + { + if (what != -1) + { + *mbuf++ = '-'; + what = -1; + } + *mbuf++ = 'o'; + strcat(parabuf, l->value.cptr->name); + strcat(parabuf, " "); + pargs++; + if (pargs >= (MAXMODEPARAMS-2)) + { + *mbuf = '\0'; + sjoin_sendit(cptr, sptr, chptr, + parv[0]); + mbuf = modebuf; + *mbuf = parabuf[0] = '\0'; + pargs = what = 0; + } + l->flags &= ~MODE_CHANOP; + } + if (l->flags & MODE_VOICE) + { + if (what != -1) + { + *mbuf++ = '-'; + what = -1; + } + *mbuf++ = 'v'; + strcat(parabuf, l->value.cptr->name); + strcat(parabuf, " "); + pargs++; + if (pargs >= (MAXMODEPARAMS-2)) + { + *mbuf = '\0'; + sjoin_sendit(cptr, sptr, chptr, + parv[0]); + mbuf = modebuf; + *mbuf = parabuf[0] = '\0'; + pargs = what = 0; + } + l->flags &= ~MODE_VOICE; + } + } + } + if (mbuf != modebuf) + { + *mbuf = '\0'; + sjoin_sendit(cptr, sptr, chptr, parv[0]); + } + + *modebuf = *parabuf = '\0'; + if (parv[3][0] != '0' && keepnewmodes) + channel_modes(sptr, modebuf, parabuf, chptr); + else + { + modebuf[0] = '0'; + modebuf[1] = '\0'; + } + + sprintf(t, ":%s SJOIN %ld %s %s %s :", parv[0], tstosend, parv[2], + modebuf, parabuf); + t += strlen(t); + + mbuf = modebuf; + parabuf[0] = '\0'; + pargs = 0; + *mbuf++ = '+'; + + for (s = s0 = strtoken(&p, parv[args+4], " "); s; + s = s0 = strtoken(&p, NULL, " ")) + { + fl = 0; + if (*s == '@' || s[1] == '@') + fl |= MODE_CHANOP; + if (*s == '+' || s[1] == '+') + fl |= MODE_VOICE; + if (!keepnewmodes) + if (fl & MODE_CHANOP) + fl = MODE_DEOPPED; + else + fl = 0; + while (*s == '@' || *s == '+') + s++; + if (!(acptr = find_chasing(sptr, s, NULL))) + continue; + if (acptr->from != cptr) + continue; + people++; + if (!IsMember(acptr, chptr)) + { + add_user_to_channel(chptr, acptr, fl); + sendto_channel_butserv(chptr, acptr, ":%s JOIN :%s", + s, parv[2]); + sendto_match_TS_servs(0, chptr, cptr, ":%s JOIN :%s", + s, parv[2]); + } + if (keepnewmodes) + strcpy(t, s0); + else + strcpy(t, s); + t += strlen(t); + *t++ = ' '; + if (fl & MODE_CHANOP) + { + *mbuf++ = 'o'; + strcat(parabuf, s); + strcat(parabuf, " "); + pargs++; + if (pargs >= (MAXMODEPARAMS-2)) + { + *mbuf = '\0'; + sjoin_sendit(cptr, sptr, chptr, parv[0]); + mbuf = modebuf; + *mbuf++ = '+'; + parabuf[0] = '\0'; + pargs = 0; + } + } + if (fl & MODE_VOICE) + { + *mbuf++ = 'v'; + strcat(parabuf, s); + strcat(parabuf, " "); + pargs++; + if (pargs >= (MAXMODEPARAMS-2)) + { + *mbuf = '\0'; + sjoin_sendit(cptr, sptr, chptr, parv[0]); + mbuf = modebuf; + *mbuf++ = '+'; + parabuf[0] = '\0'; + pargs = 0; + } + } + } + + *mbuf = '\0'; + if (pargs) + sjoin_sendit(cptr, sptr, chptr, parv[0]); + if (people) + { + if (t[-1] == ' ') + t[-1] = '\0'; + else + *t = '\0'; + sendto_match_TS_servs(1, chptr, cptr, "%s", sjbuf); + } + } + + + #ifdef TSDEBUG + /* this code is for debugging purposes only and should be removed in the + ** definitive version of TSora... besides, it's illegible -orabidoo + */ + int m_ts(cptr, sptr, parc, parv) + aClient *cptr, *sptr; + int parc; + char *parv[]; + { + aClient *acptr; + aChannel *chptr; + + if (check_registered_user(sptr)) + return 0; + sendto_one(sptr, ":%s 999 %s :Time delta is: %ld", me.name, sptr->name, timedelta); + if (parc > 1) + { + if (*parv[1] == '#' || *parv[1] == '&') + { + chptr = get_channel(sptr, parv[1], 0); + if (!chptr) + { + sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), + me.name, parv[0], parv[1]); + return 0; + } + sendto_one(sptr, ":%s 999 %s :Channel - %s : %ld", + me.name, sptr->name, chptr->chname, + chptr->channelts); + } + else + { + acptr = find_chasing(sptr, parv[1], NULL); + if (!acptr) + return 0; + sendto_one(sptr, ":%s 999 %s :User - %s : %ld", + me.name, sptr->name, acptr->name, + acptr->tsinfo); + } + return 0; + } + for (acptr = client; acptr; acptr = acptr->next) + { + if (IsPerson(acptr)) + sendto_one(sptr, ":%s 999 %s :User - %s : %ld", me.name, + sptr->name, acptr->name, acptr->tsinfo); + else if (IsServer(acptr) && MyConnect(acptr)) + sendto_one(sptr, ":%s 999 %s :Server - %s (%s)", me.name, + sptr->name, acptr->name, + (DoesTS(acptr) ? "does TS" : "no TS")); + } + for (chptr = channel; chptr; chptr = chptr->nextch) + sendto_one(sptr, ":%s 999 %s :Channel - %s : %ld", me.name, + sptr->name, chptr->chname, chptr->channelts); + return 0; + } + + #endif + + diff -c -r -N irc2.8.21+CSr15/ircd/dich_conf.c irc2.8.21+CSr16/ircd/dich_conf.c *** irc2.8.21+CSr15/ircd/dich_conf.c Wed Dec 31 18:00:00 1969 --- irc2.8.21+CSr16/ircd/dich_conf.c Wed Dec 20 00:07:27 1995 *************** *** 0 **** --- 1,505 ---- + /* + * The dich_conf.h and dich_conf.c were written to provide a generic interface + * for configuration lines matching. + * I decided to write it after I read Roy's K: line tree patch and was guided + * by the following question : why use a tree ? + * The idea of the tree is to have a left branch and a right branch, with + * "higher" or "lower" entries on one side or the other : that's the same as + * dichotomizing, which only requires an ordered list. + * These routines are meant for fast matching. There is no notion of "best" + * of "first" (meaning the order in which the lines are read) match. + * Therefore, the following functions are fit for K: lines matching but not + * I: lines matching (as sad as it may be). + * Other kinds of configuration lines aren't as time consuming or just aren't + * use for matching so it's irrelevant to try and use these functions for + * anything else. However, I still made them as generic as possible, just + * in case. + * + * -Soleil (Philippe Levan) + * + */ + + #include + #include "struct.h" + #include "common.h" + #include "sys.h" + #include "numeric.h" + #include "dich_conf.h" + + #ifndef SYSV + #define memmove(x,y,N) bcopy(y,x,N) + #endif + + /* + * The following 2 functions are, in part, borrowed from Roy's K: line tree + * patch -Sol + */ + void + reverse(s) + char s[]; + { + /* Reverse a string, from K&R C 2nd ed. -roy */ + + int c, i, j; + for (i = 0, j = strlen(s)-1; i < j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } + } + + /* + * This function decides whether a string may be used with ordered lists. + * It returns 1 if the string can be stored as is in an ordered list. + * -1 means the string has to be reversed. A string that can't be put in + * an ordered list yields 0 and should be manipulated with the linear + * functions : l_addto_conf_list() and l_find_matching_conf(). -Sol + */ + int + sortable(my_string) + char *my_string; + { + char *p; + char *rev; + + if (!my_string) + return 0; /* NULL patterns aren't allowed in ordered + lists (will have to use linear functions) + -Sol */ + + for (p=my_string;*p && (*p == '*' || *p == '?');p++); + if (!*p) + return 0; /* only wildcards, not good -Sol */ + + for (;*p && *p != '*' && *p != '?';p++); + if (*p == 0) + return -1; /* string of the form *word : needs reversal -Sol */ + + rev = (char *) MyMalloc(strlen(my_string)+1); + strcpy(rev, my_string); + + for (p=rev;*p && (*p == '*' || *p == '?');p++); + for (;*p && *p != '*' && *p != '?';p++); + if (*p == 0) + { + MyFree(rev); + return 1; /* string of the form word* -Sol */ + } + + MyFree(rev); + return (0); + } + + /* + * The following functions extract from the conf-lines the strings + * that we need. They HAVE to allocate space to save the string. + * That space will be freed by clear_conf_list(). -Sol + */ + char * + host_field(my_conf) + aConfItem *my_conf; + { + char *tmp; + char *ptr; + + if (!my_conf || !my_conf->host) + return NULL; + + if ((ptr = strchr(my_conf->host, '@')) != NULL) + ptr++; + else + ptr = my_conf->host; + tmp = (char *) MyMalloc(strlen(ptr)+1); + strcpy(tmp, ptr); + + return tmp; + } + + char * + name_field(my_conf) + aConfItem *my_conf; + { + char *tmp; + char *ptr; + + if (!my_conf || !my_conf->name) + return NULL; + + if ((ptr = strchr(my_conf->name, '@')) != NULL) + ptr++; + else + ptr = my_conf->host; + tmp = (char *) MyMalloc(strlen(ptr)+1); + strcpy(tmp, ptr); + + return tmp; + } + + char * + rev_host_field(my_conf) + aConfItem *my_conf; + { + char *tmp; + char *ptr; + + if (!my_conf || !my_conf->host) + return NULL; + + if ((ptr = strchr(my_conf->host, '@')) != NULL) + ptr++; + else + ptr = my_conf->host; + tmp = (char *) MyMalloc(strlen(ptr)+1); + strcpy(tmp, ptr); + reverse(tmp); + + return tmp; + } + + char * + rev_name_field(my_conf) + aConfItem *my_conf; + { + char *tmp; + char *ptr; + + if (!my_conf || !my_conf->name) + return NULL; + + if ((ptr = strchr(my_conf->name, '@')) != NULL) + ptr++; + else + ptr = my_conf->host; + tmp = (char *) MyMalloc(strlen(ptr)+1); + strcpy(tmp, ptr); + reverse(tmp); + + return tmp; + } + + /* + * In order not to realloc memory space each time we add an entry, we do it + * in blocks of 100 ConfEntry structures. Returns 1 if we reallocated. -Sol + */ + static int + grow_list(my_list) + aConfList *my_list; + { + unsigned int length = my_list->length; + aConfEntry *base = my_list->conf_list; + + if ((length % 100) == 0) + { + /* List is going to grow : allocate 100 more entries -Sol */ + aConfEntry *new; + + new = (aConfEntry *) MyMalloc((length+100)*sizeof(aConfEntry)); + memcpy(new, base, length*sizeof(aConfEntry)); + if (base) + { + memcpy(new, base, length*sizeof(aConfEntry)); + MyFree(base); + } + my_list->conf_list = base = new; + + return 1; + } + + return 0; + } + + /* + * This function inserts an entry at the correct location (lexicographicaly + * speakin) in the configuration list. + * If the field chosen as a criteria is already in the list, we chain the + * new entry. -Sol + */ + void + addto_conf_list(my_list, my_conf, cmp_field) + aConfList *my_list; + aConfItem *my_conf; + char *(*cmp_field)(); + { + char *field = cmp_field(my_conf); + unsigned int length = my_list->length; + aConfEntry *base = my_list->conf_list; + register unsigned int lower = 0; + register unsigned int upper = length-1; + register unsigned int compare = (length-1)/2; + register int pos; + + if (!field) + return; /* Reject NULL patterns -Sol */ + + if (!length) + { + /* List is still empty : add the entry and exit -Sol */ + if (grow_list(my_list)) + base = my_list->conf_list; + base->pattern = field; + base->conf = my_conf; + base->next = NULL; + my_list->length++; + return; + } + + while (lower != upper) + { + pos = strcmp(field, base[compare].pattern); + if (pos == 0) + { + lower = upper = compare; + break; + } + else + if (pos < 0) + upper = compare; + else + if (lower == compare) + lower = compare+1; + else + lower = compare; + compare = (lower+upper)/2; + } + + pos = strcmp(field, base[compare].pattern); + + if (!pos) + { + aConfEntry *new; + + MyFree(field); + new = (aConfEntry *) MyMalloc(sizeof(aConfEntry)); + new->pattern = NULL; + new->conf = my_conf; + new->next = base[compare].next; + base[compare].next = new; + } + else + { + if (grow_list(my_list)) + base = my_list->conf_list; + if (pos > 0) + { + /* Add after -Sol */ + memmove(&base[compare+2], &base[compare+1], + (length-1-compare)*sizeof(aConfEntry)); + base[compare+1].pattern = field; + base[compare+1].conf = my_conf; + base[compare+1].next = NULL; + } + else + { + /* Add before -Sol */ + memmove(&base[compare+1], &base[compare], + (length-compare)*sizeof(aConfEntry)); + base[compare].pattern = field; + base[compare].conf = my_conf; + base[compare].next = NULL; + } + my_list->length++; + } + } + + /* + * As the name says : this clears a configuration list. -Sol + */ + void + clear_conf_list(my_list) + aConfList *my_list; + { + if (!my_list) + return; + + if (my_list->conf_list) + { + int current; + + /* Loop through all patterns to free conf-entries + with the same pattern -Sol */ + for (current = 0; current < my_list->length; current++) + { + aConfEntry *ptr = &my_list->conf_list[current]; + + while (ptr->next) + { + aConfEntry *tmp = ptr->next->next; + + if (ptr->next->pattern) + MyFree(ptr->next->pattern); + MyFree(ptr->next); + ptr->next = tmp; + } + if (ptr->pattern) + MyFree(ptr->pattern); + } + MyFree(my_list->conf_list); + } + + my_list->length = 0; + my_list->conf_list = NULL; + } + + /* + * This function returns the first matching configuration line if both + * my_list and tomatch aren't NULL. Otherwise, it returns the next one. + * It yields NULL if there are no (more) matches. -Sol + */ + aConfItem * + find_matching_conf(my_list, tomatch) + aConfList *my_list; + char *tomatch; + { + static aConfEntry *base; + static aConfEntry *offset; + static unsigned int lower, upper, compare; + static char *name; + int dont_match = 0; + + if (my_list && tomatch) + if (!my_list->length) + { + lower = upper = compare = -1; + return NULL; + } + + if (!my_list || !tomatch) + { + if (lower == -1) + return NULL; + + if (offset && offset->next) + { + offset = offset->next; + return offset->conf; + } + + dont_match = 1; + } + else + { + base = my_list->conf_list; + lower = 0; + upper = my_list->length-1; + compare = (lower+upper)/2; + name = tomatch; + offset = NULL; + } + + while (lower != upper) + { + int pos; + + if (!dont_match) + { + if (!matches(base[compare].pattern, name)) + { + offset = &base[compare]; + return base[compare].conf; + } + } + else + dont_match = 0; + + pos = strcmp(name, base[compare].pattern); + + if (pos < 0) + upper = compare; + else + if (lower == compare) + lower = compare+1; + else + lower = compare; + compare = (lower+upper)/2; + } + + if (!dont_match) + { + if (!matches(base[compare].pattern, name)) + { + offset = &base[compare]; + return base[compare].conf; + } + } + + lower = upper = compare = -1; + return NULL; + } + + /* + * This simply adds a configuration line at the end of the list. + * Of course, it makes no sense to use addto_conf_list() and + * l_addto_conf_list() on the same list unless you want to garble it. -Sol + */ + void + l_addto_conf_list(my_list, my_conf, cmp_field) + aConfList *my_list; + aConfItem *my_conf; + char *(*cmp_field)(); + { + char *field = cmp_field(my_conf); + unsigned int length = my_list->length; + aConfEntry *base; + + (void) grow_list(my_list); + base = my_list->conf_list; + + base[length].pattern = field; + base[length].conf = my_conf; + base[length].next = NULL; + my_list->length++; + } + + /* + * This looks for the first match in the list if my_list and tomatch are both + * not NULL, otherwise it will return the next match. + * NULL means there are no (more) matches. + * This should be used only on lists created with l_addto_conf_list() since + * it won't test the "next" attribute of aConfEntry, therefore missing entries + * if there were chained entries. -Sol + */ + aConfItem * + l_find_matching_conf(my_list, tomatch) + aConfList *my_list; + char *tomatch; + { + static aConfEntry *base; + static unsigned int current; + static unsigned int length; + static char *name; + + if (my_list && tomatch) + if (!my_list->length) + { + current = -1; + return NULL; + } + + if (!my_list || !tomatch) + { + if (current == -1) + return NULL; + current++; + } + else + { + base = my_list->conf_list; + current = 0; + length = my_list->length; + name = tomatch; + } + + while (current < length) + { + if (!base[current].pattern) + return base[current].conf; /* Let's say NULL + matches all -Sol */ + else + if (!matches(base[current].pattern, name)) + return base[current].conf; + current++; + } + + current = -1; + return NULL; + } diff -c -r -N irc2.8.21+CSr15/ircd/dich_conf.h irc2.8.21+CSr16/ircd/dich_conf.h *** irc2.8.21+CSr15/ircd/dich_conf.h Wed Dec 31 18:00:00 1969 --- irc2.8.21+CSr16/ircd/dich_conf.h Tue Dec 19 18:59:03 1995 *************** *** 0 **** --- 1,54 ---- + /* + * The dich_conf.h and dich_conf.c were written to provide a generic interface + * for configuration lines matching. + * I decided to write it after I read Roy's K: line tree patch and was guided + * by the following question : why use a tree ? + * The idea of the tree is to have a left branch and a right branch, with + * "higher" or "lower" entries on one side or the other : that's the same as + * dichotomizing, which only requires an ordered list. + * These routines are meant for fast matching. There is no notion of "best" + * of "first" (meaning the order in which the lines are read) match. + * Therefore, the following functions are fit for K: lines matching but not + * I: lines matching (as sad as it may be). + * Other kinds of configuration lines aren't as time consuming or just aren't + * use for matching so it's irrelevant to try and use these functions for + * anything else. However, I still made them as generic as possible, just + * in case. + * + * -Soleil (Philippe Levan) + * + */ + + #ifndef __dich_conf_h__ + #define __dich_conf_h__ + + #include "struct.h" + + typedef struct ConfList aConfList; + typedef struct ConfEntry aConfEntry; + + struct ConfList + { + unsigned int length; + aConfEntry *conf_list; + }; + + struct ConfEntry + { + char *pattern; + aConfItem *conf; + aConfEntry *next; + }; + + extern void addto_conf_list(); + extern void clear_conf_list(); + extern aConfItem *find_matching_conf(); + extern void l_addto_conf_list(); + extern aConfItem *l_find_matching_conf(); + extern char *host_field(); + extern char *name_field(); + extern char *rev_host_field(); + extern char *rev_name_field(); + extern int sortable(); + + #endif diff -c -r -N irc2.8.21+CSr15/ircd/hash.c irc2.8.21+CSr16/ircd/hash.c *** irc2.8.21+CSr15/ircd/hash.c Sun Nov 12 18:11:59 1995 --- irc2.8.21+CSr16/ircd/hash.c Wed Dec 20 00:00:04 1995 *************** *** 27,34 **** #include "h.h" #ifdef DOUGH_HASH ! #define MAX_INITIAL 1024 ! #define MAX_INITIAL_MASK 0x3ff #define BITS_PER_COL 3 #define BITS_PER_COL_MASK 0x7 --- 27,34 ---- #include "h.h" #ifdef DOUGH_HASH ! #define MAX_INITIAL 4096 ! #define MAX_INITIAL_MASK (MAX_INITIAL-1) #define BITS_PER_COL 3 #define BITS_PER_COL_MASK 0x7 diff -c -r -N irc2.8.21+CSr15/ircd/ircd.c irc2.8.21+CSr16/ircd/ircd.c *** irc2.8.21+CSr15/ircd/ircd.c Fri Oct 20 16:01:13 1995 --- irc2.8.21+CSr16/ircd/ircd.c Tue Dec 19 19:59:16 1995 *************** *** 882,890 **** ** ping times) --msa */ #ifdef DOG3 ! if (now >= nextping && !lifesux) #else ! if (now >= nextping) #endif nextping = check_pings(now); --- 882,890 ---- ** ping times) --msa */ #ifdef DOG3 ! if ((now >= nextping && !lifesux) || rehashed) #else ! if ((now >= nextping) || rehashed) #endif nextping = check_pings(now); diff -c -r -N irc2.8.21+CSr15/ircd/s_bsd.c irc2.8.21+CSr16/ircd/s_bsd.c *** irc2.8.21+CSr15/ircd/s_bsd.c Sun Nov 12 16:54:30 1995 --- irc2.8.21+CSr16/ircd/s_bsd.c Mon Dec 18 21:01:59 1995 *************** *** 109,114 **** --- 109,116 ---- static char readbuf[READBUFSIZE]; #endif + extern ts_val timedelta; + /* * Try and find the correct name to use with getrlimit() for setting the max. * number of files allowed to be open by this process. *************** *** 938,943 **** --- 940,947 ---- sendto_ops("Lost N-Line for %s", get_client_name(cptr,FALSE)); return -1; } + sendto_one(cptr, "SVINFO %d %d %d :%ld", TS_CURRENT, TS_MIN, + (ts_servcount() == 0 ? 1 : 0), (ts_val)time(NULL)+timedelta); sendto_one(cptr, "SERVER %s 1 :%s", my_name_for_link(me.name, aconf), me.info); if (!IsDead(cptr)) diff -c -r -N irc2.8.21+CSr15/ircd/s_conf.c irc2.8.21+CSr16/ircd/s_conf.c *** irc2.8.21+CSr15/ircd/s_conf.c Sun Nov 12 18:18:25 1995 --- irc2.8.21+CSr16/ircd/s_conf.c Tue Dec 19 20:06:02 1995 *************** *** 71,76 **** --- 71,87 ---- #include "h.h" + #include "comstud.h" + + #ifdef USE_DICH_CONF + #include "dich_conf.h" + + /* Lists to do K: line matching -Sol */ + aConfList KList1 = { 0, NULL }; /* ordered */ + aConfList KList2 = { 0, NULL }; /* ordered, reversed */ + aConfList KList3 = { 0, NULL }; /* what we can't sort */ + #endif + static int check_time_interval PROTO((char *, char *)); static int lookup_confhost PROTO((aConfItem *)); *************** *** 619,624 **** --- 630,641 ---- if (sig != 2) flush_cache(); + + #ifdef USE_DICH_CONF + clear_conf_list(&KList1); + clear_conf_list(&KList2); + clear_conf_list(&KList3); + #endif (void) initconf(0); close_listeners(); *************** *** 955,960 **** --- 972,1000 ---- if (portnum < 0 && aconf->port >= 0) portnum = aconf->port; } + + #ifdef USE_DICH_CONF + if ((aconf->status & CONF_KILL) && aconf->host) + { + char *host = host_field(aconf); + + switch (sortable(host)) + { + case 0 : + l_addto_conf_list(&KList3, aconf, host_field); + break; + case 1 : + addto_conf_list(&KList1, aconf, host_field); + break; + case -1 : + addto_conf_list(&KList2, aconf, rev_host_field); + break; + } + + free(host); + } + #endif + (void)collapse(aconf->host); (void)collapse(aconf->name); Debug((DEBUG_NOTICE, *************** *** 1037,1042 **** --- 1077,1086 ---- { char reply[256], *host, *name; aConfItem *tmp; + #ifdef USE_DICH_CONF + char *rev; + aConfList *list; + #endif /* USE_DICH_CONF */ if (!cptr->user) return 0; *************** *** 1050,1055 **** --- 1094,1171 ---- reply[0] = '\0'; + #ifdef USE_DICH_CONF + rev = (char *) malloc(strlen(host)+1); + strcpy(rev, host); + reverse(rev); + + /* Start with hostnames of the form "*word" (most frequent) -Sol */ + list = &KList2; + while ((tmp = find_matching_conf(list, rev)) != NULL) + { + if (tmp->name && (!name || !match(tmp->name, name)) && + (!tmp->port || (tmp->port == cptr->acpt->port))) + { + if (BadPtr(tmp->passwd)) + goto matched; + if (is_comment(tmp->passwd)) + goto matched; + if (check_time_interval(tmp->passwd, reply)) + goto matched; + } + list = NULL; + } + + /* Try hostnames of the form "word*" -Sol */ + list = &KList1; + while ((tmp = find_matching_conf(list, host)) != NULL) + { + if (tmp->name && (!name || !match(tmp->name, name)) && + (!tmp->port || (tmp->port == cptr->acpt->port))) + { + if (BadPtr(tmp->passwd)) + goto matched; + if (is_comment(tmp->passwd)) + goto matched; + if (check_time_interval(tmp->passwd, reply)) + goto matched; + } + list = NULL; + } + + /* If none of the above worked, try non-sorted entries -Sol */ + list = &KList3; + while ((tmp = l_find_matching_conf(list, host)) != NULL) + { + if (tmp->host && tmp->name && (!name || !match(tmp->name, name)) + && (!tmp->port || (tmp->port == cptr->acpt->port))) + { + if (BadPtr(tmp->passwd)) + goto matched; + if (is_comment(tmp->passwd)) + goto matched; + if (check_time_interval(tmp->passwd, reply)) + goto matched; + } + list = NULL; + } + + matched: + free(rev); + + # ifdef DICH_CONF_DEBUG + if (reply[0] || tmp) + sendto_ops("%s matched line : K:%s:%s:%s:%d:%d", + get_client_name(cptr, FALSE), + tmp->host ? tmp->host : "", + tmp->passwd ? tmp->passwd : "", + tmp->name ? tmp->name : "", + tmp->port, get_conf_class(tmp)); + # endif /* DICH_CONF_DEBUG */ + + #endif /* USE_DICH_CONF */ + + #if !defined(USE_DICH_CONF) || defined(DICH_CONF_DEBUG) for (tmp = conf; tmp; tmp = tmp->next) if ((tmp->status == CONF_KILL) && tmp->host && tmp->name && (match(tmp->host, host) == 0) && *************** *** 1063,1068 **** --- 1179,1185 ---- if (check_time_interval(tmp->passwd, reply)) break; } + #endif /* !USE_DICH_CONF || DICH_CONF_DEBUG */ if (reply[0]) sendto_one(cptr, reply, me.name, ERR_YOUREBANNEDCREEP, cptr->name); diff -c -r -N irc2.8.21+CSr15/ircd/s_debug.c irc2.8.21+CSr16/ircd/s_debug.c *** irc2.8.21+CSr15/ircd/s_debug.c Fri Oct 20 16:01:13 1995 --- irc2.8.21+CSr16/ircd/s_debug.c Tue Dec 19 01:10:37 1995 *************** *** 203,208 **** --- 203,214 ---- #ifdef DOG3 '3', #endif + ' ', + 'T', + 'S', + #ifdef TSDEBUG + 'd', + #endif '\0'}; #include "numeric.h" diff -c -r -N irc2.8.21+CSr15/ircd/s_misc.c irc2.8.21+CSr16/ircd/s_misc.c *** irc2.8.21+CSr15/ircd/s_misc.c Fri Oct 20 16:01:13 1995 --- irc2.8.21+CSr16/ircd/s_misc.c Tue Dec 19 23:11:05 1995 *************** *** 363,372 **** on_for = time(NULL) - sptr->firsttime; # if defined(USE_SYSLOG) && defined(SYSLOG_USERS) if (IsPerson(sptr)) ! syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s@%s\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600)/60, on_for % 60, sptr->user->username, sptr->user->host); # else { --- 363,373 ---- on_for = time(NULL) - sptr->firsttime; # if defined(USE_SYSLOG) && defined(SYSLOG_USERS) if (IsPerson(sptr)) ! syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s!%s@%s\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600)/60, on_for % 60, + sptr->name, sptr->user->username, sptr->user->host); # else { *************** *** 385,394 **** (logfile = open(FNAME_USERLOG, O_WRONLY|O_APPEND)) != -1) { (void)irc_sprintf(linebuf, ! "%s (%3d:%02d:%02d): %s@%s [%s]\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600)/60, on_for % 60, sptr->user->username, sptr->user->host, sptr->username); (void)write(logfile, linebuf, strlen(linebuf)); --- 386,396 ---- (logfile = open(FNAME_USERLOG, O_WRONLY|O_APPEND)) != -1) { (void)irc_sprintf(linebuf, ! "%s (%3d:%02d:%02d): %s!%s@%s [%s]\n", myctime(sptr->firsttime), on_for / 3600, (on_for % 3600)/60, on_for % 60, + sptr->name, sptr->user->username, sptr->user->host, sptr->username); (void)write(logfile, linebuf, strlen(linebuf)); diff -c -r -N irc2.8.21+CSr15/ircd/s_serv.c irc2.8.21+CSr16/ircd/s_serv.c *** irc2.8.21+CSr15/ircd/s_serv.c Fri Oct 20 16:01:13 1995 --- irc2.8.21+CSr16/ircd/s_serv.c Mon Dec 18 21:01:59 1995 *************** *** 51,56 **** --- 51,58 ---- int max_connection_count = 1, max_client_count = 1; #endif + extern ts_val timedelta; + /* ** m_functions execute protocol messages on this server: ** *************** *** 360,365 **** --- 362,410 ---- } /* + ** ts_servcount + ** returns the number of TS servers that are connected to us + */ + int ts_servcount() + { + Reg1 int i; + Reg2 aClient *acptr; + Reg3 int r = 0; + + for (i = 0; i <= highest_fd; i++) + if ((acptr = local[i]) && IsServer(acptr) && DoesTS(acptr)) + r++; + return r; + } + + /* + ** m_svinfo + ** parv[0] = sender prefix + ** parv[1] = TS_CURRENT for the server + ** parv[2] = TS_MIN for the server + ** parv[3] = server is standalone or connected to non-TS only + ** parv[4] = server's idea of UTC time + */ + int m_svinfo(cptr, sptr, parc, parv) + aClient *cptr, *sptr; + int parc; + char *parv[]; + { + Reg1 ts_val v; + + if (cptr != sptr || (!IsUnknown(cptr) && !IsHandshake(cptr)) || + parc < 5 || TS_CURRENT < atoi(parv[2]) || atoi(parv[1]) < TS_MIN) + return 0; + + if (atoi(parv[3])) + v = (atol(parv[4]) - (ts_val)time(NULL) - timedelta) / 2; + else + v = atol(parv[4]) - (ts_val)time(NULL) - timedelta; + cptr->tsinfo = (v ? v : (ts_val)TS_LEAVEIT); + return 0; + } + + /* ** m_server ** parv[0] = sender prefix ** parv[1] = servername *************** *** 606,614 **** --- 651,686 ---- } + static void sendnick_TS(cptr, acptr) + aClient *cptr, *acptr; + { + static char ubuf[12]; + + if (IsPerson(acptr)) + { + send_umode(NULL, acptr, 0, SEND_UMODES, + ubuf); + if (!*ubuf) + strcpy(ubuf, "+"); + sendto_one(cptr, "NICK %s %d %ld %s %s %s %s :%s", acptr->name, + acptr->hopcount + 1, acptr->tsinfo, ubuf, + acptr->user->username, acptr->user->host, + acptr->user->server, acptr->info); + } + else if (IsService(acptr)) + { + sendto_one(cptr,"NICK %s :%d", + acptr->name, + acptr->hopcount + 1); + sendto_one(cptr,":%s SERVICE * * :%s", acptr->name, + acptr->info); + } + } + int m_server_estab(cptr) Reg1 aClient *cptr; { + Reg1 aChannel *chptr; Reg2 aClient *acptr; Reg3 aConfItem *aconf, *bconf; char *inpath, *host, *s, *encr; *************** *** 681,686 **** --- 753,761 ---- /* ** Pass my info to the new server */ + sendto_one(cptr, "SVINFO %d %d %d :%ld", TS_CURRENT, TS_MIN, + (ts_servcount() == 0 ? 1 : 0), + (ts_val)time(NULL) + timedelta); sendto_one(cptr, "SERVER %s 1 :%s", my_name_for_link(me.name, aconf), (me.info[0]) ? (me.info) : "IRCers United"); *************** *** 704,709 **** --- 779,791 ---- *s = '@'; } + if (cptr->tsinfo && cptr->tsinfo != (ts_val)TS_LEAVEIT && + !DoesTS(cptr) && ts_servcount() == 0) + timedelta += cptr->tsinfo; + + if (cptr->tsinfo) + cptr->tsinfo = TS_DOESTS; + det_confs_butmask(cptr, CONF_LEAF|CONF_HUB|CONF_NOCONNECT_SERVER); /* ** *WARNING* *************** *** 802,843 **** } } ! for (acptr = &me; acptr; acptr = acptr->prev) { ! /* acptr->from == acptr for acptr == cptr */ ! if (acptr->from == cptr) ! continue; ! if (IsPerson(acptr)) { /* ** IsPerson(x) is true only when IsClient(x) is true. ** These are only true when *BOTH* NICK and USER have ** been received. -avalon */ ! sendto_one(cptr,"NICK %s :%d",acptr->name, ! acptr->hopcount + 1); ! sendto_one(cptr,":%s USER %s %s %s :%s", acptr->name, ! acptr->user->username, acptr->user->host, ! acptr->user->server, acptr->info); ! send_umode(cptr, acptr, 0, SEND_UMODES, buf); ! send_user_joins(cptr, acptr); ! } ! else if (IsService(acptr)) ! { ! sendto_one(cptr,"NICK %s :%d", ! acptr->name, acptr->hopcount + 1); ! sendto_one(cptr,":%s SERVICE * * :%s", ! acptr->name, acptr->info); } ! } ! /* ! ** Last, pass all channels plus statuses ! */ ! { ! Reg1 aChannel *chptr; for (chptr = channel; chptr; chptr = chptr->nextch) send_channel_modes(cptr, chptr); ! } return 0; } --- 884,976 ---- } } ! if (DoesTS(cptr)) { ! Link *l; ! static char nickissent = 1; ! ! /* ! ** Send it in the shortened format with the TS, if ! ** it's a TS server; walk the list of channels, sending ! ** all the nicks that haven't been sent yet for each ! ** channel, then send the channel itself -- it's less ! ** obvious than sending all nicks first, but on the ! ** receiving side memory will be allocated more nicely ! ** saving a few seconds in the handling of a split ! ** -orabidoo ! */ ! ! nickissent = 3 - nickissent; ! /* flag used for each nick to check if we've sent it ! yet - must be different each time and !=0, so we ! alternate between 1 and 2 -orabidoo ! */ ! for (chptr = channel; chptr; chptr = chptr->nextch) { + for (l = chptr->members; l; l = l->next) + { + acptr = l->value.cptr; + if (acptr->nicksent != nickissent) + { + acptr->nicksent = nickissent; + if (acptr->from != cptr) + sendnick_TS(cptr, acptr); + } + } + send_channel_modes(cptr, chptr); + } + /* + ** also send out those that are not on any channel + */ + for (acptr = &me; acptr; acptr = acptr->prev) + if (acptr->nicksent != nickissent) + { + acptr->nicksent = nickissent; + if (acptr->from != cptr) + sendnick_TS(cptr, acptr); + } + + } + else + { + /* + ** do it the usual way, for non-TS servers -orabidoo + */ + for (acptr = &me; acptr; acptr = acptr->prev) + { + /* acptr->from == acptr for acptr == cptr */ + if (acptr->from == cptr) + continue; + if (IsPerson(acptr)) + { /* ** IsPerson(x) is true only when IsClient(x) is true. ** These are only true when *BOTH* NICK and USER have ** been received. -avalon */ ! sendto_one(cptr,"NICK %s :%d",acptr->name, ! acptr->hopcount + 1); ! sendto_one(cptr, ! ":%s USER %s %s %s :%s", acptr->name, ! acptr->user->username, acptr->user->host, ! acptr->user->server, acptr->info); ! send_umode(cptr, acptr, 0, SEND_UMODES, buf); ! send_user_joins(cptr, acptr); ! } ! else if (IsService(acptr)) ! { ! sendto_one(cptr,"NICK %s :%d", ! acptr->name, acptr->hopcount + 1); ! sendto_one(cptr,":%s SERVICE * * :%s", ! acptr->name, acptr->info); ! } } ! /* ! ** Last, pass all channels plus statuses ! */ for (chptr = channel; chptr; chptr = chptr->nextch) send_channel_modes(cptr, chptr); ! } return 0; } diff -c -r -N irc2.8.21+CSr15/ircd/s_user.c irc2.8.21+CSr16/ircd/s_user.c *** irc2.8.21+CSr15/ircd/s_user.c Sun Nov 12 17:14:56 1995 --- irc2.8.21+CSr16/ircd/s_user.c Mon Dec 18 22:41:33 1995 *************** *** 37,45 **** #include #include "h.h" ! void send_umode_out PROTO((aClient*, aClient *, int)); void send_umode PROTO((aClient *, aClient *, int, int, char *)); static char buf[BUFSIZE], buf2[BUFSIZE]; #ifdef CLONE_CHECK --- 37,48 ---- #include #include "h.h" ! void send_umode_out PROTO((aClient*, aClient *, int, int)); void send_umode PROTO((aClient *, aClient *, int, int, char *)); + int do_user PROTO((char *, aClient *, aClient*, char *, char *, char *, + char *)); + extern ts_val timedelta; static char buf[BUFSIZE], buf2[BUFSIZE]; #ifdef CLONE_CHECK *************** *** 47,52 **** --- 50,73 ---- extern char clonekillhost[100]; #endif + static int user_modes[] = { FLAGS_OPER, 'o', + FLAGS_LOCOP, 'O', + FLAGS_INVISIBLE, 'i', + FLAGS_WALLOP, 'w', + FLAGS_SERVNOTICE, 's', + #ifdef FK_USERMODES + FLAGS_FMODE, 'f', + #endif + FLAGS_UMODE, 'u', + #ifdef CLIENT_NOTICES + FLAGS_CMODE, 'c', + #endif + #ifdef FK_USERMODES + FLAGS_KMODE, 'k', + #endif + FLAGS_RMODE, 'r', + 0, 0 }; + /* ** m_functions execute protocol messages on this server: ** *************** *** 337,342 **** --- 358,365 ---- ** available. Doing it is not so simple though, would have ** to implement the following: ** + ** (actually it has been implemented already for a while) -orabidoo + ** ** 1) user telnets in and gives only "NICK foobar" and waits ** 2) another user far away logs in normally with the nick ** "foobar" (quite legal, as this server didn't propagate *************** *** 356,361 **** --- 379,385 ---- Reg1 aConfItem *aconf; char *parv[3]; char *temp; + static char ubuf[12]; short oldstatus = sptr->status; anUser *user = sptr->user; int i; *************** *** 632,643 **** } } ! sendto_serv_butone(cptr, "NICK %s :%d", nick, sptr->hopcount+1); ! sendto_serv_butone(cptr, ":%s USER %s %s %s :%s", nick, user->username, user->host, user->server, sptr->info); ! if (MyConnect(sptr)) ! send_umode_out(cptr, sptr, 0); #ifdef USE_SERVICES check_services_butone(SERVICE_WANT_NICK, sptr, "NICK %s :%d", nick, sptr->hopcount); --- 656,675 ---- } } ! send_umode(NULL, sptr, 0, SEND_UMODES, ubuf); ! if (!*ubuf) ! strcpy(ubuf, "+"); ! ! sendto_TS_serv_butone(0, cptr, "NICK %s :%d", nick, sptr->hopcount+1); ! sendto_TS_serv_butone(0, cptr, ":%s USER %s %s %s :%s", nick, user->username, user->host, user->server, sptr->info); ! sendto_TS_serv_butone(1, cptr, "NICK %s %d %ld %s %s %s %s :%s", ! nick, sptr->hopcount+1, sptr->tsinfo, ubuf, ! user->username, user->host, user->server, ! sptr->info); ! if (ubuf[1]) ! send_umode_out(cptr, sptr, 0, 0); #ifdef USE_SERVICES check_services_butone(SERVICE_WANT_NICK, sptr, "NICK %s :%d", nick, sptr->hopcount); *************** *** 653,658 **** --- 685,697 ---- ** m_nick ** parv[0] = sender prefix ** parv[1] = nickname + ** parv[2] = optional hopcount when new user; TS when nick change + ** parv[3] = optional TS + ** parv[4] = optional umode + ** parv[5] = optional username + ** parv[6] = optional hostname + ** parv[7] = optional server + ** parv[8] = optional ircname */ int m_nick(cptr, sptr, parc, parv) aClient *cptr, *sptr; *************** *** 661,673 **** { aClient *acptr; char nick[NICKLEN+2], *s; ! if (parc < 2) { sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } if (MyConnect(sptr) && (s = (char *)index(parv[1], '~'))) *s = '\0'; strncpyzt(nick, parv[1], NICKLEN+1); --- 700,724 ---- { aClient *acptr; char nick[NICKLEN+2], *s; ! ts_val newts = 0; ! int doests, sameuser = 0; ! if (parc < 2) { sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); return 0; } + if (!IsServer(sptr) && IsServer(cptr)) + if (parc > 2) + newts = atol(parv[2]); + else + newts = sptr->tsinfo; + else if (parc > 3 && IsServer(cptr)) + newts = atol(parv[3]); + + doests = (IsServer(cptr) && DoesTS(cptr)); + if (MyConnect(sptr) && (s = (char *)index(parv[1], '~'))) *s = '\0'; strncpyzt(nick, parv[1], NICKLEN+1); *************** *** 810,846 **** ** same time, or net reconnecting) or just two net fragmens becoming ** joined and having same nicks in use. We cannot have TWO users with ** same nick--purge this NICK from the system with a KILL... >;) - ** - ** The client indicated by 'acptr' is dead meat, give at least some - ** indication of the reason why we are just dropping it cold. */ - sendto_one(acptr, err_str(ERR_NICKCOLLISION), - me.name, acptr->name, acptr->name); /* ** This seemingly obscure test (sptr == cptr) differentiates ** between "NICK new" (TRUE) and ":old NICK new" (FALSE) forms. */ ! if (sptr == cptr) { ! sendto_ops("Nick collision on %s(%s <- %s)", ! acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! /* ! ** A new NICK being introduced by a neighbouring ! ** server (e.g. message type "NICK new" received) ! */ ! ircstp->is_kill++; ! sendto_serv_butone(NULL, /* all servers */ ! ":%s KILL %s :%s (%s <- %s)", ! me.name, acptr->name, me.name, ! acptr->from->name, /* NOTE: Cannot use get_client_name twice ** here, it returns static string pointer: ** the other info would be lost */ get_client_name(cptr, FALSE)); ! acptr->flags |= FLAGS_KILLED; ! return exit_client(cptr, acptr, &me, "Nick collision"); } /* ** A NICK change has collided (e.g. message type --- 861,932 ---- ** same time, or net reconnecting) or just two net fragmens becoming ** joined and having same nicks in use. We cannot have TWO users with ** same nick--purge this NICK from the system with a KILL... >;) */ /* ** This seemingly obscure test (sptr == cptr) differentiates ** between "NICK new" (TRUE) and ":old NICK new" (FALSE) forms. */ ! /* ! ** Changed to something reasonable like IsServer(sptr) ! ** (true if "NICK new", false if ":old NICK new") -orabidoo ! */ ! ! if (IsServer(sptr)) { ! /* ! ** A new NICK being introduced by a neighbouring ! ** server (e.g. message type "NICK new" received) ! */ ! sameuser = (parc > 5) && ! mycmp(acptr->user->username, parv[5]) == 0 && ! mycmp(acptr->user->host, parv[6]) == 0; ! if (!doests || !newts || !acptr->tsinfo ! || (newts == acptr->tsinfo)) ! { ! sendto_ops("Nick collision on %s(%s <- %s)(both killed)", ! acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! ircstp->is_kill++; ! sendto_one(acptr, err_str(ERR_NICKCOLLISION), ! me.name, acptr->name, acptr->name); ! sendto_serv_butone(NULL, /* all servers */ ! ":%s KILL %s :%s (%s <- %s)", ! me.name, acptr->name, me.name, ! acptr->from->name, /* NOTE: Cannot use get_client_name twice ** here, it returns static string pointer: ** the other info would be lost */ + get_client_name(cptr, FALSE)); + acptr->flags |= FLAGS_KILLED; + return exit_client(cptr, acptr, &me, "Nick collision"); + } + else if ((sameuser && newts < acptr->tsinfo) || + (!sameuser && newts > acptr->tsinfo)) + return 0; + else + { + if (sameuser) + sendto_ops("Nick collision on %s(%s <- %s)(older killed)", + acptr->name, acptr->from->name, get_client_name(cptr, FALSE)); ! else ! sendto_ops("Nick collision on %s(%s <- %s)(newer killed)", ! acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! ! ircstp->is_kill++; ! sendto_one(acptr, err_str(ERR_NICKCOLLISION), ! me.name, acptr->name, acptr->name); ! sendto_serv_butone(sptr, /* all servers but sptr */ ! ":%s KILL %s :%s (%s <- %s)", ! me.name, acptr->name, me.name, ! acptr->from->name, ! get_client_name(cptr, FALSE)); ! acptr->flags |= FLAGS_KILLED; ! (void)exit_client(cptr, acptr, &me, "Nick collision"); ! goto nickkilldone; ! } } /* ** A NICK change has collided (e.g. message type *************** *** 849,871 **** ** must be killed from the incoming connection, and "old" must ** be purged from all outgoing connections. */ ! sendto_ops("Nick change collision from %s to %s(%s <- %s)", ! sptr->name, acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! ircstp->is_kill++; ! sendto_serv_butone(NULL, /* KILL old from outgoing servers */ ! ":%s KILL %s :%s (%s(%s) <- %s)", me.name, sptr->name, me.name, acptr->from->name, ! acptr->name, get_client_name(cptr, FALSE)); ! ircstp->is_kill++; ! sendto_serv_butone(NULL, /* Kill new from incoming link */ ! ":%s KILL %s :%s (%s <- %s(%s))", ! me.name, acptr->name, me.name, acptr->from->name, ! get_client_name(cptr, FALSE), sptr->name); ! acptr->flags |= FLAGS_KILLED; ! (void)exit_client(NULL, acptr, &me, "Nick collision(new)"); ! sptr->flags |= FLAGS_KILLED; ! return exit_client(cptr, sptr, &me, "Nick collision(old)"); nickkilldone: if (IsServer(sptr)) --- 935,1009 ---- ** must be killed from the incoming connection, and "old" must ** be purged from all outgoing connections. */ ! sameuser = mycmp(acptr->user->username, sptr->user->username) == 0 && ! mycmp(acptr->user->host, acptr->user->host) == 0; ! if (!doests || !newts || !acptr->tsinfo || (newts == acptr->tsinfo)) ! { ! sendto_ops("Nick change collision from %s to %s(%s <- %s)(both killed)", ! sptr->name, acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! ircstp->is_kill++; ! sendto_one(acptr, err_str(ERR_NICKCOLLISION), ! me.name, acptr->name, acptr->name); ! sendto_serv_butone(NULL, /* KILL old from outgoing servers */ ! ":%s KILL %s :%s (%s(%s) <- %s)", ! me.name, sptr->name, me.name, acptr->from->name, ! acptr->name, get_client_name(cptr, FALSE)); ! ircstp->is_kill++; ! sendto_serv_butone(NULL, /* Kill new from incoming link */ ! ":%s KILL %s :%s (%s <- %s(%s))", ! me.name, acptr->name, me.name, acptr->from->name, ! get_client_name(cptr, FALSE), sptr->name); ! acptr->flags |= FLAGS_KILLED; ! (void)exit_client(NULL, acptr, &me, "Nick collision(new)"); ! sptr->flags |= FLAGS_KILLED; ! return exit_client(cptr, sptr, &me, "Nick collision(old)"); ! } ! else if ((sameuser && newts < acptr->tsinfo) || ! (!sameuser && newts > acptr->tsinfo)) ! { ! if (sameuser) ! sendto_ops("Nick change collision from %s to %s(%s <- %s)(older killed)", ! sptr->name, acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! else ! sendto_ops("Nick change collision from %s to %s(%s <- %s)(newer killed)", ! sptr->name, acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! ircstp->is_kill++; ! sendto_serv_butone(cptr, /* KILL old from outgoing servers */ ! ":%s KILL %s :%s (%s(%s) <- %s)", me.name, sptr->name, me.name, acptr->from->name, ! acptr->name, get_client_name(cptr, FALSE)); ! sptr->flags |= FLAGS_KILLED; ! if (sameuser) ! return exit_client(cptr, sptr, &me, "Nick collision(old)"); ! else ! return exit_client(cptr, sptr, &me, "Nick collision(new)"); ! } ! else ! { ! if (sameuser) ! sendto_ops("Nick collision on %s(%s <- %s)(older killed)", ! acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! else ! sendto_ops("Nick collision on %s(%s <- %s)(newer killed)", ! acptr->name, acptr->from->name, ! get_client_name(cptr, FALSE)); ! ! ircstp->is_kill++; ! sendto_one(acptr, err_str(ERR_NICKCOLLISION), ! me.name, acptr->name, acptr->name); ! sendto_serv_butone(sptr, /* all servers but sptr */ ! ":%s KILL %s :%s (%s <- %s)", ! me.name, acptr->name, me.name, ! acptr->from->name, ! get_client_name(cptr, FALSE)); ! acptr->flags |= FLAGS_KILLED; ! (void)exit_client(cptr, acptr, &me, "Nick collision"); ! /* goto nickkilldone; */ ! } nickkilldone: if (IsServer(sptr)) *************** *** 876,881 **** --- 1014,1049 ---- add_client_to_list(sptr); if (parc > 2) sptr->hopcount = atoi(parv[2]); + if (newts) + sptr->tsinfo = newts; + else + newts = sptr->tsinfo = (ts_val)time(NULL) + timedelta; + /* copy the nick in place */ + (void)strcpy(sptr->name, nick); + (void)add_to_client_hash_table(nick, sptr); + if (parc > 8) + { + Reg1 int *s, flag; + Reg2 char *m; + + /* + ** parse the usermodes -orabidoo + */ + m = &parv[4][1]; + while (*m) + { + for (s = user_modes; (flag = *s); s += 2) + if (*m == *(s+1)) + { + sptr->flags |= flag&SEND_UMODES; + break; + } + m++; + } + + return do_user(nick, cptr, sptr, parv[5], parv[6], + parv[7], parv[8]); + } } else if (sptr->name[0]) { *************** *** 884,893 **** ** on a channel, send note of change to all clients ** on that channel. Propagate notice to other servers. */ sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); if (sptr->user) add_history(sptr); ! sendto_serv_butone(cptr, ":%s NICK :%s", parv[0], nick); #ifdef USE_SERVICES check_services_butone(SERVICE_WANT_NICK, sptr, ":%s NICK :%s", parv[0], nick); --- 1052,1073 ---- ** on a channel, send note of change to all clients ** on that channel. Propagate notice to other servers. */ + if (mycmp(parv[0], nick) || (!MyClient(sptr) && parc > 2 && + newts < sptr->tsinfo)) + sptr->tsinfo = newts ? newts : (ts_val)time(NULL) + + timedelta; sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); if (sptr->user) add_history(sptr); ! if (sptr->tsinfo) ! { ! sendto_TS_serv_butone(1, cptr, ":%s NICK %s :%ld", ! parv[0], nick, sptr->tsinfo); ! sendto_TS_serv_butone(0, cptr, ":%s NICK :%s", parv[0], ! nick); ! } ! else ! sendto_serv_butone(cptr, ":%s NICK :%s", parv[0], nick); #ifdef USE_SERVICES check_services_butone(SERVICE_WANT_NICK, sptr, ":%s NICK :%s", parv[0], nick); *************** *** 899,904 **** --- 1079,1085 ---- /* This had to be copied here to avoid problems.. */ (void)strcpy(sptr->name, nick); + sptr->tsinfo = time(NULL) + timedelta; if (sptr->user) /* ** USER already received, now we have NICK. *************** *** 1449,1454 **** --- 1630,1639 ---- *buf = '\0'; len = 0; } + #ifdef TSDEBUG + if (is_deopped(acptr, chptr)) + *(buf + len++) = '-'; + #endif if (is_chan_op(acptr, chptr)) *(buf + len++) = '@'; else if (has_voice(acptr, chptr)) *************** *** 1513,1519 **** { #define UFLAGS (FLAGS_INVISIBLE|FLAGS_WALLOP|FLAGS_SERVNOTICE) char *username, *host, *server, *realname; - anUser *user; if (parc > 2 && (username = (char *)index(parv[1],'@'))) *username = '\0'; --- 1698,1703 ---- *************** *** 1536,1541 **** --- 1720,1738 ---- server = (parc < 4 || BadPtr(parv[3])) ? "" : parv[3]; realname = (parc < 5 || BadPtr(parv[4])) ? "" : parv[4]; + return do_user(parv[0], cptr, sptr, username, host, server, realname); + } + + + /* + ** do_user + */ + int do_user(nick, cptr, sptr, username, host, server, realname) + aClient *cptr, *sptr; + char *nick, *username, *host, *server, *realname; + { + anUser *user; + user = make_user(sptr); if (!MyConnect(sptr)) *************** *** 1548,1554 **** if (!IsUnknown(sptr)) { sendto_one(sptr, err_str(ERR_ALREADYREGISTRED), ! me.name, parv[0]); return 0; } #ifndef NO_DEFAULT_INVISIBLE --- 1745,1751 ---- if (!IsUnknown(sptr)) { sendto_one(sptr, err_str(ERR_ALREADYREGISTRED), ! me.name, nick); return 0; } #ifndef NO_DEFAULT_INVISIBLE *************** *** 2052,2058 **** sptr->user->username, sptr->user->host, IsOper(sptr) ? 'O' : 'o'); sptr->flags |= (FLAGS_SERVNOTICE|FLAGS_WALLOP|FLAGS_CMODE|FLAGS_KMODE); ! send_umode_out(cptr, sptr, old); sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]); #if !defined(CRYPT_OPER_PASSWORD) && (defined(FNAME_OPERLOG) ||\ (defined(USE_SYSLOG) && defined(SYSLOG_OPER))) --- 2249,2255 ---- sptr->user->username, sptr->user->host, IsOper(sptr) ? 'O' : 'o'); sptr->flags |= (FLAGS_SERVNOTICE|FLAGS_WALLOP|FLAGS_CMODE|FLAGS_KMODE); ! send_umode_out(cptr, sptr, old, 1); sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]); #if !defined(CRYPT_OPER_PASSWORD) && (defined(FNAME_OPERLOG) ||\ (defined(USE_SYSLOG) && defined(SYSLOG_OPER))) *************** *** 2297,2320 **** } #endif - static int user_modes[] = { FLAGS_OPER, 'o', - FLAGS_LOCOP, 'O', - FLAGS_INVISIBLE, 'i', - FLAGS_WALLOP, 'w', - FLAGS_SERVNOTICE, 's', - #ifdef FK_USERMODES - FLAGS_FMODE, 'f', - #endif - FLAGS_UMODE, 'u', - #ifdef CLIENT_NOTICES - FLAGS_CMODE, 'c', - #endif - #ifdef FK_USERMODES - FLAGS_KMODE, 'k', - #endif - FLAGS_RMODE, 'r', - 0, 0 }; - /* * m_umode() added 15/10/91 By Darren Reed. * parv[0] - sender --- 2494,2499 ---- *************** *** 2444,2450 **** * compare new flags with old flags and send string which * will cause servers to update correctly. */ ! send_umode_out(cptr, sptr, setflags); return 0; } --- 2623,2629 ---- * compare new flags with old flags and send string which * will cause servers to update correctly. */ ! send_umode_out(cptr, sptr, setflags, 1); return 0; } *************** *** 2504,2512 **** /* * added Sat Jul 25 07:30:42 EST 1992 */ ! void send_umode_out(cptr, sptr, old) aClient *cptr, *sptr; ! int old; { Reg1 int i; Reg2 aClient *acptr; --- 2683,2694 ---- /* * added Sat Jul 25 07:30:42 EST 1992 */ ! /* ! * extra argument evenTS added to send to TS servers or not -orabidoo ! */ ! void send_umode_out(cptr, sptr, old, evenTS) aClient *cptr, *sptr; ! int old, evenTS; { Reg1 int i; Reg2 aClient *acptr; *************** *** 2517,2526 **** # endif for (i = highest_fd; i >= 0; i--) if ((acptr = local[i]) && IsServer(acptr) && ! (acptr != cptr) && (acptr != sptr) && *buf) sendto_one(acptr, ":%s MODE %s :%s", sptr->name, sptr->name, buf); if (cptr && MyClient(cptr)) send_umode(cptr, sptr, old, ALL_UMODES, buf); } --- 2699,2710 ---- # endif for (i = highest_fd; i >= 0; i--) if ((acptr = local[i]) && IsServer(acptr) && ! (acptr != cptr) && (acptr != sptr) && *buf && ! (evenTS || !DoesTS(acptr))) sendto_one(acptr, ":%s MODE %s :%s", sptr->name, sptr->name, buf); if (cptr && MyClient(cptr)) send_umode(cptr, sptr, old, ALL_UMODES, buf); } +