In case someone is still interested, I quit working on this script a couple of days after my last post in this topic, but here is my last version:

Code:
;UPnP Script v1.22

alias upnp.debugpermanent {
  if ($isid) return $false
}
on *:start: {
  upnp.start
  if ($upnp.debugpermanent) .debug -i upnp.dcc upnp.dccdebug
}
on *:unload: {
  unset %upnp.*
}
on *:exit: {
  unset %upnp.*
}
on ^*:logon:*: {
  if ($serverip == 84.16.238.88) halt
  if ($readini($mircini,ident,active) == yes) upnp.addPortMapping TCP $readini($mircini,ident,port)
  set %upnp.IdentdMap $true
}
on *:error:*: {
  if ($serverip == 84.16.238.88) halt
  if ($readini($mircini,ident,active) == yes) && (%upnp.IdentdMap) upnp.delPortMapping TCP $readini($mircini,ident,port)
}
on *:connect: {
  if ($serverip == 84.16.238.88) halt
  if ($readini($mircini,ident,active) == yes) upnp.delPortMapping TCP $readini($mircini,ident,port)
  unset %upnp.IdentdMap
}
alias debug {
  if ((%upnp.debuguse) || ($upnp.debugpermanent)) && ($gettok($debug,-1,92) == upnp.dcc) {
    linesep $iif($active == Status Window,-s,$active)
    echo -a -UPNP- Debug is in use.
    linesep $iif($active == Status Window,-s,$active)
  }
  else {
    debug $1-
    if ($0 > 0) set %upnp.debugparams $$1-
  }
}
alias upnp.dccgetnum {
  if (!$isid) return
  var %i = 0
  if ($$1 == send) {
    while (%i <= $send(0)) {
      if ($send(%i).wid == $$2) return %i
      inc %i
    }
  }
  else {
    while (%i <= $chat(0)) {
      if ($chat(%i).wid == $$2) return %i
      inc %i
    }
  }
  return 0
}
alias upnp.dcccheck {
  var %upnp.dccnum = $upnp.dccgetnum($1,$$2)
  var %upnp.dccstatus = $iif($1 == send,$send(%upnp.dccnum).status,$chat(%upnp.dccnum).status)
  if ($istok(failed:active:sent:inactive,%upnp.dccstatus,58)) || (%upnp.dccnum == 0) {
    .timerupnp.dcc $+ $$3 off
    upnp.delPortMapping TCP $3
  }
}
alias upnp.dccdebug {
  tokenize 32 $1-
  if ($1 != ->) return
  if ($istok($+(:,$chr(1),DCC SEND,/,:,$chr(1),DCC CHAT),$5-6,47)) {
    var %upnp.debugport = $remove($9,$chr(1))
    upnp.addPortMapping TCP %upnp.debugport
    .timerupnp.dcc $+ %upnp.debugport 0 0 upnp.dcccheck $6 $iif($6 == send,$send($send($4,0)).wid,$chat($chat($4,0)).wid) %upnp.debugport
    if (!$upnp.debugpermanent) {
      unset %upnp.debuguse
      .debug off
      if (%upnp.debugbefore) {
        .debug %upnp.debugparamsbefore
        unset %upnp.debugbefore
        unset %upnp.debugparamsbefore
      }
    }  
  }
  return
}
alias dcc {
  if ($isid) return
  if ($istok(send:chat,$1,58)) && (!$upnp.debugpermanent) {
    if ($debug != $null) {
      set %upnp.debugparamsbefore %upnp.debugparams      
      .debug off
      set %upnp.debugbefore $true
    }
    unset %upnp.dccdebuguse
    .debug -i upnp.dcc upnp.dccdebug
    set %upnp.debuguse $true
  }
  if ($gettok($debug,-1,92) != upnp.dcc) && ($upnp.debugpermanent) {
    .debug -i upnp.dcc upnp.dccdebug
  }
  dcc $1-
}
alias upnp.start {
  unset %upnp.*
  var %upnp.discip = 239.255.255.250
  var %upnp.disclocalport = $rand(10000,63999)
  while (!$portfree(%upnp.disclocalport)) {
    %upnp.disclocalport = $rand(10000,63999)
  }
  echo $color(other) -gs -UPnP- Searching for Internet Gateway...
  sockclose upnp.discover
  sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900 $+(M-SEARCH * HTTP/1.1,$crlf,Host: 239.255.255.250:1900,$crlf,Man: "ssdp:discover",$crlf,ST: urn:schemas-upnp-org:service:WANIPConnection:1,$crlf,MX: 2,$str($crlf,2))
  sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900
  sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900 $+(M-SEARCH * HTTP/1.1,$crlf,Host: 239.255.255.250:1900,$crlf,Man: "ssdp:discover",$crlf,ST: urn:schemas-upnp-org:service:WANPPPConnection:1,$crlf,MX: 2,$str($crlf,2))
  sockudp -kt upnp.discover %upnp.disclocalport %upnp.discip 1900
}
alias upnp.getLocalInfo {
  set %upnp.localprevip $ip
  set %upnp.localprevhost $host
  unset %upnp.localticks  
  .localinfo -h
  .timerupnp.localip off
  set %upnp.localtimeout 5000
  set %upnp.localticks $ticks
  .timerupnp.localip 0 0 upnp.getLocalInfo.2
}
alias upnp.getLocalInfo.2 {  
  set %upnp.localip $ip
  if (%upnp.localip == $null) {
    if ($calc($ticks - %upnp.localticks) > %upnp.localtimeout) {
      echo $color(other) -gs -UPnP- Local IP not found
      .timerupnp.localip off      
      if (%upnp.localprevip != $null) {
        .localinfo $iif(%upnp.localprevhost == $null,%upnp.localprevip,%upnp.localprevhost) %upnp.localprevip
      }
    }
  }
  else {
    echo $color(other) -gs -UPnP- Local IP: $ip
    .timerupnp.localip off
    if (%upnp.localprevip != $null) {
      .localinfo $iif(%upnp.localprevhost == $null,%upnp.localprevip,%upnp.localprevhost) %upnp.localprevip
    }
  }
}
on *:udpread:upnp.discover: {
  if ($sockerr > 0) return
  sockread %info
  while ($sockbr > 0) {
    tokenize 32 %info
    if ($1 == $null) {
      echo $color(other) -gs -UPnP- Internet Gateway with %upnp.st service found at $sock($sockname).saddr
      upnp.getLocalInfo
      upnp.getDeviceInfo %upnp.discURL
      sockclose $sockname
      return
    }
    if ($gettok($1,1,58) == LOCATION) set %upnp.discURL $remove($gettok($1-,2-,58),$chr(32))
    if ($gettok($1,1,58) == ST) set %upnp.st $remove($gettok($1-,2-,58),$chr(32))
    sockread %info
  }
}
alias upnp.getDeviceInfo {
  echo $color(other) -gs -UPnP- Getting Service Info...
  var %upnp.devip = $gettok($gettok($$1,2,47),1,58)
  var %upnp.devport = $gettok($gettok($1,2,47),2,58)
  sockclose upnp.devinfo
  sockopen upnp.devinfo %upnp.devip %upnp.devport
  sockmark upnp.devinfo $+($chr(47),$gettok($1,3-,47))
}

on 1:sockopen:upnp.devinfo: {
  if ($sockerr > 0) return
  set %upnp.devinfoMode HTTP
  set %upnp.getCURL $false
  sockwrite -nt $sockname GET $sock($sockname).mark HTTP/1.1
  sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
  sockwrite -nt $sockname Connection: close
  sockwrite -nt $sockname Accept-Language: en
  sockwrite -nt $sockname
}
on *:sockread:upnp.devinfo: {
  if ($sockerr > 0) return
  sockread %info
  while ($sockbr > 0) {
    tokenize 32 %info
    if (%upnp.devinfoMode == XML) {
      if (<URLBase> isin $1-) {
        set %upnp.servinfoBase $upnp.getXMLValue($1-,<URLBase>)
        echo $color(other) -gs -UPnP- Service Base URL: %upnp.servinfoBase
      }
      if (!%upnp.getCURL) {
        if ($+(<serviceType>,%upnp.st,</serviceType>) isin $1-) set %upnp.getCURL $true
      }
      if (%upnp.getCURL) { 
        if (<controlURL> isin $1-) {          
          set %upnp.servinfoURL $upnp.getXMLValue($1-,<controlURL>)
          set %upnp.getCURL $false
          echo $color(other) -gs -UPnP- Service Control URL: %upnp.servinfoURL
          upnp.getServiceExternalIP $+(%upnp.servinfoBase,%upnp.servinfoURL)
        }
      }
    }
    if ($1 == $null) && (%upnp.devinfoMode == HTTP) set %upnp.devinfoMode XML
    sockread %info
  }
}
alias upnp.getServiceExternalIP {
  echo $color(other) -gs -UPnP- Getting Service External IP Address...
  var %upnp.servip = $gettok($gettok($$1,2,47),1,58)
  var %upnp.servport = $gettok($gettok($1,2,47),2,58)
  sockclose upnp.servIP
  sockopen upnp.servIP %upnp.servip %upnp.servport
  sockmark upnp.servIP $+($chr(47),$gettok($1,3-,47))
}

on 1:sockopen:upnp.servIP: {
  if ($sockerr > 0) return
  set %upnp.servIPMode HTTP
  sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
  sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
  sockwrite -nt $sockname Connection: close
  sockwrite -nt $sockname Content-Length: $iif(PPP isin %upnp.st,273,272)
  sockwrite -nt $sockname Content-Type: text/xml; charset="utf-8"
  sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#GetExternalIPAddress")
  sockwrite -nt $sockname
  sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  sockwrite -nt $sockname <s:Body>
  sockwrite -nt $sockname $+(<u:GetExternalIPAddress xmlns:u=",%upnp.st,"></u:GetExternalIPAddress>)
  sockwrite -nt $sockname </s:Body>
  sockwrite -nt $sockname </s:Envelope>
  sockwrite -nt $sockname
}
on *:sockread:upnp.servIP: {
  if ($sockerr > 0) return
  sockread %info
  while ($sockbr > 0) {
    tokenize 32 %info
    if (%upnp.servIPMode == XML) {
      if (<NewExternalIPAddress> isin $1-) {
        set %upnp.externalIP $upnp.getXMLValue($1-,<NewExternalIPAddress>)
        echo $color(other) -gs -UPnP- Service External IP Address: %upnp.externalIP
      }
    }
    if ($1 == $null) && (%upnp.servIPMode == HTTP) set %upnp.servIPMode XML
    sockread %info
  }
}
alias upnp.addPortMapping {
  var %upnp.lp = $iif($0 > 2,$3,$$2)
  var %upnp.prot = $upper($iif($0 > 2,$2,$1))
  var %upnp.curl = $iif($0 > 2,$1,$+(%upnp.servinfoBase,%upnp.servinfoURL))
  if (%upnp.localip == $null) {
    echo $color(other) -gs -UPnP- Cannot map port %upnp.lp $+($chr(40),%upnp.prot,$chr(41)) $+ . Local IP Address is unknown
    return
  }
  echo $color(other) -gs -UPnP- Mapping port %upnp.lp $+($chr(40),%upnp.prot,$chr(41)) to %upnp.localip $+ ...
  var %upnp.pmi = $gettok($gettok(%upnp.curl,2,47),1,58)
  var %upnp.pmp = $gettok($gettok(%upnp.curl,2,47),2,58)
  set %upnp.pmport %upnp.lp
  set %upnp.pmprot %upnp.prot
  set %upnp.pmlease 0
  sockclose upnp.pm
  sockopen upnp.pm %upnp.pmi %upnp.pmp
  sockmark upnp.pm $+($chr(47),$gettok(%upnp.curl,3-,47))
}
on 1:sockopen:upnp.pm: {
  if ($sockerr > 0) return
  set %upnp.pmMode HTTP
  sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
  sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
  sockwrite -nt $sockname Connection: close
  sockwrite -nt $sockname Content-Length: $calc(527 + $len(%upnp.st) + ($len(%upnp.pmport) * 4) + ($len(%upnp.pmprot) * 2) + ($len(%upnp.localip) * 2) + $len(%upnp.pmlease))
  sockwrite -nt $sockname Content-Type: text/xml; charset="utf-8"
  sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#AddPortMapping")
  sockwrite -nt $sockname
  sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  sockwrite -nt $sockname <s:Body>
  sockwrite -nt $sockname $+(<u:AddPortMapping xmlns:u=",%upnp.st,">)
  sockwrite -nt $sockname <NewRemoteHost></NewRemoteHost>
  sockwrite -nt $sockname $+(<NewExternalPort>,%upnp.pmport,</NewExternalPort>)
  sockwrite -nt $sockname $+(<NewProtocol>,%upnp.pmprot,</NewProtocol>)
  sockwrite -nt $sockname $+(<NewInternalPort>,%upnp.pmport,</NewInternalPort>)
  sockwrite -nt $sockname $+(<NewInternalClient>,%upnp.localip,</NewInternalClient>)
  sockwrite -nt $sockname <NewEnabled>1</NewEnabled>
  sockwrite -nt $sockname $+(<NewPortMappingDescription>mIRC $chr(40),%upnp.localip,:,%upnp.pmport,$chr(41),$chr(32),%upnp.pmport,$chr(32),%upnp.pmprot,</NewPortMappingDescription>)
  sockwrite -nt $sockname $+(<NewLeaseDuration>,%upnp.pmlease,</NewLeaseDuration>)
  sockwrite -nt $sockname </u:AddPortMapping>
  sockwrite -nt $sockname </s:Body>
  sockwrite -nt $sockname </s:Envelope>
  sockwrite -nt $sockname
}
on *:sockread:upnp.pm: {
  if ($sockerr > 0) return
  sockread %info
  while ($sockbr > 0) {
    tokenize 32 %info
    if (%upnp.pmMode == HTTP) {
      if (HTTP/1.1 200 * iswm $1-) {
        echo $color(other) -gs -UPnP- Port Mapping Added: $+(mIRC $chr(40),%upnp.localip,:,%upnp.pmport,$chr(41),$chr(32),%upnp.pmport,$chr(32),%upnp.pmprot)
        sockclose $sockname
        return
      }
      if (HTTP/1.1 500 * iswm $1-) {
        echo $color(other) -gs -UPnP- Port Mapping Add Error
        sockclose $sockname
        return
      }
      if ($1 == $null) set %upnp.pmMode XML
    }
    if (%upnp.pmMode == XML) {
      ;if ($+(<u:AddPortMappingResponse xmlns:u=",%upnp.st,"/>) isin $1-) {
      ;}
    }
    sockread %info
  }
}
alias upnp.delPortMapping {
  var %upnp.lp = $iif($0 > 2,$3,$$2)
  var %upnp.prot = $upper($iif($0 > 2,$2,$1))
  var %upnp.curl = $iif($0 > 2,$1,$+(%upnp.servinfoBase,%upnp.servinfoURL))
  echo $color(other) -gs -UPnP- Deleting Port Mapping for port %upnp.lp $+($chr(40),%upnp.prot,$chr(41)) $+ ...
  var %upnp.pmdi = $gettok($gettok(%upnp.curl,2,47),1,58)
  var %upnp.pmdp = $gettok($gettok(%upnp.curl,2,47),2,58)
  set %upnp.pmdport %upnp.lp
  set %upnp.pmdprot %upnp.prot
  sockclose upnp.pmd
  sockopen upnp.pmd %upnp.pmdi %upnp.pmdp
  sockmark upnp.pmd $+($chr(47),$gettok(%upnp.curl,3-,47))
}

on 1:sockopen:upnp.pmd: {
  if ($sockerr > 0) return
  set %upnp.pmdMode HTTP
  sockwrite -nt $sockname POST $sock($sockname).mark HTTP/1.1
  sockwrite -nt $sockname Host: $+($sock($sockname).ip,$chr(58),$sock($sockname).port)
  sockwrite -nt $sockname Connection: close
  sockwrite -nt $sockname Content-Length: $calc(321 + $len(%upnp.st) + $len(%upnp.pmdport) + $len(%upnp.pmdprot))
  sockwrite -nt $sockname Content-Tupe: text/xml; charset="utf-8"
  sockwrite -nt $sockname SOAPAction: $+(",%upnp.st,#DeletePortMapping")
  sockwrite -nt $sockname
  sockwrite -nt $sockname <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  sockwrite -nt $sockname <s:Body>
  sockwrite -nt $sockname $+(<u:DeletePortMapping xmlns:u=",%upnp.st,">)
  sockwrite -nt $sockname <NewRemoteHost></NewRemoteHost>
  sockwrite -nt $sockname $+(<NewExternalPort>,%upnp.pmdport,</NewExternalPort>)
  sockwrite -nt $sockname $+(<NewProtocol>,%upnp.pmdprot,</NewProtocol>)
  sockwrite -nt $sockname </u:DeletePortMapping>
  sockwrite -nt $sockname </s:Body>
  sockwrite -nt $sockname </s:Envelope>
  sockwrite -nt $sockname
}
on *:sockread:upnp.pmd: {
  if ($sockerr > 0) return
  sockread %info
  while ($sockbr > 0) {
    tokenize 32 %info
    if (%upnp.pmdMode == HTTP) {
      if (HTTP/1.1 200 * iswm $1-) {
        echo $color(other) -gs -UPnP- Port Mapping Deleted for port %upnp.pmdport $+($chr(40),%upnp.pmdprot,$chr(41))
        sockclose $sockname
        return
      }
      if (HTTP/1.1 500 * iswm $1-) {
        echo $color(other) -gs -UPnP- Port Mapping Delete Error
        sockclose $sockname
        return
      }
      if ($1 == $null) set %upnp.pmdMode XML
    }
    if (%upnp.pmdMode == XML) {
      ;if ($+(<u:DeletePortMappingResponse xmlns:u=",%upnp.st,"/>) isin $1-) {
      ;}
    }
    sockread %info
  }
}
alias upnp.getXMLValue {
  if (!$isid) return  
  var %rest = $right($$1-,$calc(0 - ($pos($1-,$2) + $len($2) - 1)))
  var %tag = $2
  if ($pos(%rest,<) != 1) return $gettok(%rest,1,$asc(<))
  else return $null
}


I remember fixing a bug in the "on 1:sockopen:upnp.pmd" event (there was a "%upnp.pmport" that should have been "%upnp.pmdport") and changing the parameters that both the upnp.addPortMapping and upnp.delPortMapping methods take; they now take [Control URL] <TCP|UDP> <port>.

I've been using it for a couple of months now without having any problems. In case this script is unable to close a port it opened thanks to a crash or something similar, you can manually close it with the upnp.delPortMapping method. Hell, you can even close ports that were left open by another application. Ports opened by UPnP usually show up in your router's configuration page, and if you have a mess for whatever reason (for example, sometimes MSN Messenger and BT clients will leave a lot of ports open), unplugging your router should be enough to clear them all.