What you're doing here, every time you pass $regex(%text,....) it is filling the $regml(n) with all the urls in the text.
$regex() it self will return the total number of matches, if this is 1, 2, 3 or 4 or what ever it may be, you'll do $regml(1) (or the total amount of matches)
What you need to do, is simple store the amount of matches to a variable and loop through all $regml(n) until you've been through the list.
Also worth a note you could make sure you're likely to want to try and capture the text inside your text event and use the 'strip' modifier as below.
on ^*:text:/ftp|http|www/iS:?: {
var %i = $regex(%text,/((?:ftp:\/\/|https?:\/\/|www2?\.)[^<>\.\s]+(?:\.[^<>\.\s]+)+(?:\/[^<>\.\s]+)*)/giS)
while (%i) {
if ($read(system\url.txt,w,$regml(%i) == $null) write system\url.txt $regml(%i)
dec %i
}
if ($dialog(url)) loadbuf -ro url 1 system\url.txt
}