Note: The mainteinance of the scripting examples is discontinued since I no longer have an interest to continue doing so. The pages will remain here, for now, but that might not be the case in the future. You are free to download all the material on these pages and set a up mirror, or even continue the maintenance of the material by enhancing the examples yourself.
All the material in these examples are for the mIRC version 6.03. It is very likely that some or most of these examples won't work in future versions.
One of the biggest drawbacks of current IRC protocol are net-splits. Net-splits happen when two or more servers in the same network lose connection to each other. When a split happens, your server sends you quit messages for all the nicks that were connected to the servers that now disconnected from your part of the network.
[16:24] * Fred has quit IRC (irc.fu-berlin.de irc.stealth.net)
[16:24] * Jack has quit IRC (irc.fu-berlin.de irc.stealth.net)
[16:24] * Sheila has quit IRC (irc.fu-berlin.de irc.stealth.net)
[16:24] * John has quit IRC (irc.fu-berlin.de irc.stealth.net)
[16:24] * Juan has quit IRC (irc.fu-berlin.de irc.onenet.es)
[16:24] * Raul has quit IRC (irc.fu-berlin.de irc.onenet.es)
[16:29] * Jack has joined #chat
[16:29] * Fred has joined #chat
[16:29] * Sheila has joined #chat
[16:29] * John jas joined #chat
[16:31] * Raul has joined #chat
[16:31] * Juan has joined #chat
This is an example of a situation where you are connected to a server irc.fu-berlin.de and it loses connection to irc.stealth.net and irc.onenet.es. When this happens, you get quit messages for all users of those servers. The format of quit message is usually '<connected server> <disconnected server>' like you see in the example. However some networks might display the splits differently. The RFC1459 suggests the usual way but some networks just have decided to implement things differently. Luckily, to my knowledge, these networks are a small minority. When looking back at the example, irc.stealth.net manages to reestablish the connection in five minutes. Then from your own viewpoint, all the irc.stealth.net users join back to the channels they are on. From their viewpoint it's actually you who joins to the channel. When two more minutes pass, irc.onenet.es manages to reestablish the connection when the same thing happens to irc.onenet.es users, but again, only from your viewpoint.
Some IRC clients, such as BX and irssi, have code that tries to guess when quits and joins have been caused by net-splits. I use the word guess because the protocol provides no way to know if a join has actually been generated by a server reconnecting to the network. However assuming that the network uses standard quit messages for informing about net-splits, quits can be done reliably. Without knowing how the mentioned clients work internally, the method to display more friendly net-splits is simply to put all the quit messages into a buffer which is emptied after a few seconds. If there are many similar quits, display them all in one line. Dealing with joins is a lot harder. You could try to store all the splitted nicks in a buffer and when you get a mass join, check the buffer, and draw your own conclusions. The common practise and experience from BX and irssi has shown that it's possible to do a rather reliable algorithm for interpreting joins - they might not work in bizzarre cases but a normal user will seldom encounter such situations.
I know that the example code on this page is rather hard to understand. I have done extensive comments and apart from them, I'll try to give a short description of the algorithm.
Each open channel has a hash table that is made as soon as it is needed. The name is netsplit-<cid><chanel>, for example 'netsplit-3#foobar'. The hash table will have full addresses of users as items since they are guaranteed to be unique. The data part consists of connected server and disconnected server.
Item | Data |
---|---|
Fred!ident@host.domain | irc.fu-berlin.de irc.stealth.net |
Jack!ident@host.domain | irc.fu-berlin.de irc.stealth.net |
Sheila!ident@host.domain | irc.fu-berlin.de irc.stealth.net |
John!ident@host.domain | irc.fu-berlin.de irc.stealth.net |
Juan!ident@host.domain | irc.fu-berlin.de irc.onenet.es |
Raul!ident@host.domain | irc.fu-berlin.de irc.onenet.es |
; Intelligent net-split handling
; Displays all splitted nicks in one line in the channel window instead
; of each user making one line. This does *not* handle the joins when split
; is over. That is still to be left for future release.
; Known problems:
; The splitted nicks are displayed after two seconds from the last quit
; message. There can be no fix to this problem except configure the time
; to be shorter. Note that the nicklist updates immediately without any delay.
; If a split lasts less than two seconds, the join will be displayed before
; the quit. This should be very rare but it's possible.
on ^*:QUIT: {
; A split has taken place when the quit message consists of two server
; names, nothing else (the detection method isn't foolproof but I can't
; think of anything better)
if ( (*?.??* iswm $1) && (*?.??* iswm $2) && ($0 == 2) ) {
; Handle the split for all shared channels
var %x = 1
while ( $comchan($nick,%x) ) {
; Timer will be named netsplit-<cid><channel>-<connected server>
; for example netsplit-3#foobar-^.irc.com
; Because the server may be masked, like *.de, and wildcards
; are not allowed in timer names, $replace will convert *'s to ^
var %timername = $+(netsplit-,$cid,$ifmatch,-,$replace($1,*,^))
; Hash table will be named netsplit-<cid><channel>
; for example netsplit-3#foobar
var %hashtablename = $+(netsplit-,$cid,$ifmatch)
; Set item <fulladdress> =< <connected server> <disconnected server>
hadd -m %hashtablename $fulladdress $1 $2
; Wait two seconds after each splitted user for new splits
; If two seconds have passed without new splitted nicks, all the nicks
; are finally flushed into the channel window
.timer $+ %timername 1 2 flushquits $cid $ifmatch $1
inc %x
}
; Halt the default quit message
haltdef
}
;else {
; If you have your own on QUIT event that deals with displaying quits,
; put it here
;}
}
; $1 = Connection ID, $2 = Channel, $3 = First server
alias flushquits {
; Start flushing nicks by setting the original connection as active
scid $1
; Make the hash table name from parameters, naturally using the same
; scheme as the on QUIT event
var %htable = $+(netsplit-,$1,$2)
; Get the names of splitted servers. Each user has
; "<connected server> <disconnected server>" as their data value
; so go through all users with the same connected server and
; use $addtok to get all the different servers without duplicates
var %splitservers
var %x = 1
while ( $hmatch(%htable,$3 *,%x).data ) {
; Very boring and optimized loop. The only thing you might want to
; change is the last value which specifies the separator of multiple
; servers that have been disconnected from the network. The default
; is ASCII 47 '/', so the servers are like *.de/*.pl/skynet.be
%splitservers = $addtok(%splitservers,$gettok($hget(%htable,$ifmatch),2,32),47)
inc %x
}
; Uncomment this if you want to display the splitted servers and nicks in
; separate line
;echo $color(quit text) -t $2 * Netsplit between $3 and %splitservers
; Finally go through all users and flush their quits
var %splitnicks
while ( $hmatch(%htable,$3 *,1).data ) {
; $ifmatch contains full address of a random user pulled from hash table
; Take the nick by taking the first token with ! (ASCII 33) as separator
; and just append it to %splitnicks with $addtok using , (ASCII 44) as separator
; You can modify the script to show user's full address if you wish. I just feel
; that it would take away nearly all the advantage this script is giving.
%splitnicks = $addtok(%splitnicks,$gettok($ifmatch,1,33),44)
; The loop pulls a random user, adds it to %splitnicks, and deletes the user
; from the hash table until there are no more users
hdel %htable $ifmatch
; In case the %splitnicks is about to become too long, flush it out before we
; get any line too long errors. This means that if you are witnessing a very,
; very large split, you will actually see multiple lines. There is nothing
; that can be done about that since the line length is limited to a bit more
; than 900 characters.
if ( $len(%splitnicks) > 700 ) {
echo $color(quit text) -t $2 * Lost in split ( $+ $3 and %splitservers $+ ): $sorttok(%splitnicks,44)
var %splitnicks
}
}
; Flush out all the nicks that are remaining in %splitnicks. The nicks are
; alphabetically sorted to give a nicer touch.
if ( %splitnicks != $null ) {
echo $color(quit text) -t $2 * Lost in split ( $+ $3 and %splitservers $+ ): $sorttok(%splitnicks,44)
}
; If this flush made the hash table empty, free the hash table
if ( $hget(%htable,0).item == 0 ) hfree %htable
}
[16:24] * Lost in split (irc.fu-berlin.de and irc.stealth.net/irc.onenet.es): Fred,Jack,John,Juan,Raul,Sheila
[16:29] * Jack has joined #chat
[16:29] * Fred has joined #chat
[16:29] * Sheila has joined #chat
[16:29] * John jas joined #chat
[16:31] * Raul has joined #chat
[16:31] * Juan has joined #chat
Like the sample output shows, the script doesn't deal with joins after the split. The reason for this is that making such an algorithm is very hard and I don't have resources to do extensive testing. I run the current script for about two months and fixed all the bugs I encountered. If I ever discover a simple algorithm for dealing with joins after a net-split, I promise to include it here.
There is also a downgraded version for mIRC 5.91 for those that still use 5.91.