Filesend — File Browser

Filesendv1.100 / Filesendv1.100 / filesend.mrc

filesend.mrc — 29.04 KB — Download this file

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FILESEND ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;                           ** made by Vliedel **
;
;                            ** Version 1.100 **
;
; Please report bugs and suggestions to:
;
; #Vliedel @ Quakenet
; #Filesend @ Quakenet
;
; Written and tested on mirc 6.2
;
;
; Commands:
; /filesend.client <ip> <port> <pass> <nr of times to reconnect> <nr of times to retry file> [dir]
; /filesend.server <port> <pass> <nr of times to retry port> <seconds listen time> <nr of times to reconnect> <nr of times to retry file> [dir]
; /filesend.listen.restart [port] [pass] [nr of times to retry port] [seconds listen time]
; /filesend.request <sockname> list
; /filesend.request <sockname> <fileid> [fileid] [fileid] ...
; /filesend.adddir <dir>
; /filesend.addfile.user
; /filesend.addfile.bot <filename>
; /filesend.remdir <dir>
; /filesend.remfile <fileid> [fileid] [fileid] ...
; /filesend.flist.send
; /filesend.checkpws
; /filesend.server.stop
; /filesend.client.stop
; /filesend.sockclose.msg <sockname>
; /filesend.sockclose <sockname>
;
;
; Thanks to Saturn & Albie
;
; have fun :)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


alias filesend.client { fs.start client $1- }
alias filesend.server { fs.start server $1- }
alias filesend.listen.restart { fs.start listen.restart $1- }

alias -l fs.start {
  if ($1 == client) {
    ; /filesend.client <ip> <port> <pass> <nr of times to reconnect> <nr of times to retry file> [dir]
    var %sock = filesend.client , %ip = $2 , %port = $int($3) , %pass = $4 , %r.con = $int($5) , %r.file = $int($6) , %dir = $iif($7 == $null,$scriptdirfilesend,$iif(: isin $7,$7-,$scriptdir $+ $7-))
    if ($6 == $null) || (%port !isnum 1-65535) || (%r.con !isnum 0-100) || (%r.file !isnum 0-100) {
      fs.echo -e usage: /filesend.client <ip> <port> <pass> <nr of times to reconnect> <nr of times to retry file> [dir]
      .signal filesend error %sock
      return
    }
  }
  if ($1 == server) {
    ; /filesend.server <port> <pass> <nr of times to retry port> <seconds listen time> <nr of times to reconnect> <nr of times to retry file> [dir]
    var %sock = filesend.listen , %port = $int($2) , %pass = $3 , %r.port = $int($4) , %listentime = $int($5) , %r.con = $int($6) , %r.file = $int($7) , %dir = $iif($8 == $null,$scriptdirfilesend,$iif(: isin $8,$8-,$scriptdir $+ $8-))
    if ($7 == $null) || (%port !isnum 1-65535) || (%r.port !isnum 0-100) || (%listentime !isnum 1-604800) || (%r.con !isnum 0-100) || (%r.file !isnum 0-100) {
      fs.echo -e usage: /filesend.server <port> <pass> <nr of times to retry port> <seconds listen time> <nr of times to reconnect> <nr of times to retry file> [dir]
      .signal filesend error %sock
      return
    }
  }
  if ($1 = listen.restart) {
    ; /filesend.listen.restart [port] [pass] [nr of times to retry port] [seconds listen time]
    var %sock = filesend.listen , %port = $iif($2 == $null,$hget(filesend,port.filesend.listen),$int($2)) , %pass = $iif($3 == $null,$hget(filesend,pw.filesend.listen),$3)
    var %r.port = $iif($4 == $null,$hget(filesend,retry.port.filesend.listen),$int($4)) , %listentime = $iif($5 == $null,$hget(filesend,listentime.filesend.listen),$int($5))
    if (!$sock(filesend.server.*)) || (!$hget(filesend)) {
      fs.echo -e no connections open, use /filesend.server
      .signal filesend error %sock
      return
    }
    if (%pass == $null) || (%port !isnum 1-65535) || (%r.port !isnum 0-100) || (%listentime !isnum 1-604800) {
      fs.echo -e usage: /filesend.listen.restart [port] [pass] [nr of times to retry port] [seconds listen time]
      .signal filesend error %sock
      return
    }
  }
  if ($1 !== listen.restart) && (!$isdir(%dir)) && (!$makedir(%dir)) {
    fs.echo -e Invalid folder: %dir
    .signal filesend error dl.path %sock %dir
    return
  }
  if ($sock(%sock)) {
    fs.echo Socketname $qt(%sock) is not free
    .signal filesend error sock.notfree %sock
    return
  }
  if ($1 == server) && ($sock(filesend.server.*)) {
    fs.echo One or more connections with server are in use
    .signal filesend error sock.notfree filesend.server.*
    return
  }
  if (!$hget(filesend)) { hmake filesend 100 }
  elseif ($1 == client) { hdel -w filesend *.filesend.client }
  elseif ($1 == server) { hdel -w filesend *.filesend.server.* | hdel -w filesend *.filesend.listen }
  if (!$hget(filesend,files)) { hadd filesend files 0 }
  if ($1 !== client) {
    if ($timer(filesend.server.port.retry)) { .timerfilesend.server.port.retry off }
    if (!$portfree(%port)) {
      hinc -u $+ $calc(($hget(filesend,server.port.retry.cur) + 1) * 10 + 2) filesend server.port.retry.cur
      var %r.cur = $hget(filesend,server.port.retry.cur) , %delay = $calc(%r.cur * 10)
      if (%r.cur <= %r.port) {
        .timerfilesend.server.port.retry -o 1 %delay filesend. $+ $1 $2-
        fs.echo Port %port is not free. Autoretry ( $+ %r.cur $+ / $+ %r.port $+ ) in %delay seconds
      }
      else {
        hdel filesend server.port.retry.cur
        if (!$dialog(filesend)) && (!$sock(filesend.*)) { hfree filesend }
        fs.echo Port %port is not free. No more autoretry
      }
      .signal filesend error port.notfree %sock %port %r.cur %r.port
      return
    }
    if ($hget(filesend,server.port.retry.cur) !== $null) { hdel filesend server.port.retry.cur }
  }
  if (!$hget(filesend,dl.folder)) {
    if $fopen(filesend.test) { .fclose filesend.test }
    var %ferr
    .fopen -o filesend.test $qt(%dir $+ \ filesend.testfile.txt)
    if ($ferr) { var %ferr = 1 }
    if (!%ferr) { .fwrite filesend.test test }
    if ($ferr) { var %ferr = 1 }
    if ($fopen(filesend.test)) { .fclose filesend.test }
    if (%ferr) {
      fs.echo Invalid path: %dir
      .signal filesend error dl.path %sock %dir
      return
    }
    .remove $qt(%dir $+ \ filesend.testfile.txt)
    hadd filesend dl.folder %dir
  }
  if (!$hget(filesend,ul.folder)) { hadd filesend ul.folder %dir }
  if (!$hget(filesend,maxid)) && (!$dialog(filesend)) { filesend.adddir $hget(filesend,ul.folder) }
  hadd filesend port. $+ %sock %port
  hadd filesend pw. $+ %sock %pass
  if ($1 !== listen.restart) {
    hadd filesend retry.con. $+ %sock %r.con
    hadd filesend retry.file %r.file
  }
  if ($1 !== client) {
    hadd filesend listentime.filesend.listen %listentime
    hadd filesend retry.port.filesend.listen %r.port
    if ($1 == server) { hadd filesend listen.aant 0 }
    .signal filesend socklisten. $+ $iif($1 == server,open,reopen) %port
    socklisten filesend.listen %port
    if ($sockerr) {
      fs.echo filesend.listen Socklisten error
      .timer -o 1 0 fs.sockerr filesend.listen
      return
    }
    fs.echo Listening now at filesend.listen %port
    .timerfilesend.server.checkpws -o 1 %listentime filesend.checkpws
  }
  if ($1 == client) {
    hadd filesend ip.filesend.client %ip
    sockopen filesend.client %ip %port
    if ($sockerr) {
      fs.echo filesend.client Sockopen error
      .timer -o 1 0 fs.sockerr filesend.client
      return
    }
  }
}

alias filesend.request {
  if ($sock($1).mark !=== Accepted) || ($sock($1).status !== active) || (($int($2) !isnum 1-) && ($2 !== list)) { fs.echo -e Usage: /filesend.request <sockname> <fileID> [fileID] .. or /filesend.request <sockname> list | return }
  var %i = 2
  while (%i <= $0) {
    var %req = $gettok($1-,%i,32)
    if (%req == list) { fs.queue $1 -d rl }
    elseif ($int(%req) isnum 1-) { fs.queue $1 -d rf $int(%req) }
    inc %i
  }
}

alias filesend.adddir {
  if (!$fs.listing.check) { return 0 }
  if (!$isdir($1-)) { fs.echo -e Dir $qt($1-) doesn't exist | return 0 }
  var %f = $hget(filesend,files)
  if (!%f) {
    if ($hget(fs.flist)) { hfree fs.flist }
    hmake fs.flist 1
    hadd filesend files $findfile($1-,*,0,1,fs.addfile.first $1-)
  }
  else { noop $findfile($1-,*,0,1,fs.addfile $1-) }
  if ($isid) { return $calc($hget(filesend,files) - %f) }
  elseif ($hget(filesend,files) > %f) { filesend.flist.send }
}

alias filesend.addfile.user {
  if (!$fs.listing.check) { return 0 }
  var %i = $msfile($hget(filesend,ul.folder) $+ \,Add files to upload,Add)
  if (%i == -1) { noop $input(Too many files selected.,ouw,filesend) | return 0 }
  if (!$fs.listing.check) { return 0 }
  var %f = $hget(filesend,files)
  if (!%f) {
    if ($hget(fs.flist)) { hfree fs.flist }
    hmake fs.flist 1
  }
  while (%i) { fs.addfile $msfile(%i) | dec %i }
  if ($isid) { return $calc($hget(filesend,files) - %f) }
  elseif ($hget(filesend,files) > %f) { filesend.flist.send }
}

alias filesend.addfile.bot {
  if (!$fs.listing.check) { return 0 }
  var %f = $hget(filesend,files)
  if (!%f) {
    if ($hget(fs.flist)) { hfree fs.flist }
    hmake fs.flist 1
  }
  fs.addfile $1-
  if ($isid) { return $calc($hget(filesend,files) - %f) }
  elseif ($hget(filesend,files) > %f) { filesend.flist.send }
}

alias -l fs.addfile {
  if (!$isfile($1-)) {
    fs.echo File $qt($1-) doesn't exist
    .signal filesend error addfile $1-
    return
  }
  if ($hfind(fs.flist,$1-,1,n).data) { fs.echo File $1- is already added | return }
  hinc filesend files
  hinc filesend maxid
  hadd fs.flist $hget(filesend,maxid) $1-
  fs.echo Added file $1-
  .signal filesend addfile $hget(filesend,maxid) $1-
}

alias -l fs.addfile.first {
  if (!$isfile($1-)) {
    fs.echo File $qt($1-) doesn't exist
    .signal filesend error addfile $1-
    return
  }
  hinc filesend maxid
  hadd fs.flist $hget(filesend,maxid) $1-
  fs.echo Added file $1-
  .signal filesend addfile $hget(filesend,maxid) $1-
}

alias filesend.remdir {
  if (!$fs.listing.check) { return 0 }
  if (!$isdir($1-)) { fs.echo -e Dir $qt($1-) doesn't exist | return 0 }
  var %f = $hget(filesend,files)
  noop $findfile($1-,*,0,1,fs.remfile $iif($hfind(fs.flist,$1-,1,n).data,$v1,0))
  if ($isid) { return $calc(%f - $hget(filesend,files)) }
  elseif ($hget(filesend,files) < %f) { filesend.flist.send }
}

alias filesend.remfile {
  if (!$fs.listing.check) { return 0 }
  var %i = $numtok($1-,32) , %f = $hget(filesend,files)
  while (%i) { fs.remfile $int($gettok($1-,%i,32)) | dec %i }
  if ($isid) { return $calc(%f - $hget(filesend,files)) }
  elseif ($hget(filesend,files) < %f) { filesend.flist.send }
}

alias -l fs.remfile {
  if (!$hget(fs.flist,$1)) { fs.echo File ID $1 doesn't exist | return }
  hdec filesend files
  hdel fs.flist $1
  var %i = $sock(filesend.*,0)
  while (%i) {
    var %s = $sock(filesend.*,%i) , %q2 = $hget(filesend,ul.queue.sf. $+ %s)
    if ($sock(%s).mark === Accepted) && (($gettok(%q2,1,32) !== sf $1) || ($hget(filesend,ul.status. $+ %s) !== sending)) { hadd filesend ul.queue.sf. $+ %s $remtok(%q2,sf $1,1,44) }
    dec %i
  }
  fs.echo Removed file ID $1
  .signal filesend remfile $1
}

alias -l fs.listing.check {
  var %i = $sock(filesend.*,0)
  while (%i) {
    if ($sock(filesend.*,%i).mark === Accepted) && ($sock(filesend.*,%i).status == active) && ($hget(filesend,ul.status. $+ $sock(filesend.*,%i)) == listing) {
      fs.echo -e Can't change shared files while listing.
      .signal filesend error change.flist
      return $false
    }
    dec %i
  }
  return $true
}

alias filesend.flist.send {
  var %i = $sock(filesend.*,0)
  while (%i) {
    if ($sock(filesend.*,%i).mark === Accepted) && ($sock(filesend.*,%i).status == active) { fs.queue $sock(filesend.*,%i) -n sl }
    dec %i
  }
}

alias filesend.server.stop {
  if ($sock(filesend.listen)) { sockclose filesend.listen }
  if ($hget(filesend)) {
    var %i = $sock(filesend.server.*,0)
    while (%i > 0) {
      hdel filesend sockerr. $+ $sock(filesend.server.*,%i)
      if ($sock(filesend.server.*,%i).status == active) { filesend.sockclose.msg $sock(filesend.server.*,%i) }
      dec %i
    }
  }
  sockclose filesend.server.*
  if ($timer(filesend.server.port.retry)) { .timerfilesend.server.port.retry off }
  if ($timer(filesend.server.checkpws)) { .timerfilesend.server.checkpws off }
  fs.server.closed
}

alias filesend.client.stop {
  if ($hget(filesend)) {
    hdel filesend sockerr.filesend.client
    if ($sock(filesend.client).status == active) { filesend.sockclose.msg filesend.client }
  }
  sockclose filesend.client
  fs.client.closed
}

alias -l fs.echo {
  if ($dialog(filesend)) { return }
  if (!$window(@filesend)) { window -ezk0 @filesend }
  if ($1 == -e) { echo -et @filesend $2- }
  else { echo -t @filesend $1- }
}

alias filesend.checkpws {
  .timerfilesend.server.checkpws off
  if ($sock(filesend.listen)) {
    sockclose filesend.listen
    .signal filesend socklisten.close
  }
  fs.echo filesend.listen closed
  var %i = $sock(filesend.server.*,0)
  while (%i) {
    if ($sock(filesend.server.*,%i).mark !=== Accepted) { sockclose $sock(filesend.server.*,%i) }
    dec %i
  }
  if ($hget(filesend)) { hdel -w filesend md5pw.* }
  fs.server.closed
}

on *:SOCKLISTEN:filesend.listen:{
  if ($sockerr) {
    fs.echo $sockname Socklisten error
    .timer -o 1 0 fs.sockerr $sockname
    return
  }
  hinc filesend listen.aant
  var %i = $hget(filesend,listen.aant)
  while ($sock(filesend.server. $+ %i)) { inc %i }
  hadd filesend listen.aant %i
  var %sock = filesend.server. $+ %i
  sockaccept %sock
  if ($sockerr) {
    fs.echo $sockname Sockaccept error
    .timer -o 1 0 fs.sockerr $sockname
    return
  }
  var %ch = $fs.pwgen(30,0-9 A-Z a-z)
  hadd filesend md5pw. $+ %sock $md5($hget(filesend,pw.filesend.listen) %ch)
  sockwrite -n %sock Passrequest %ch
  fs.echo %sock ( $+ $sock(%sock).ip $+ ) connected, requesting password
;  .signal filesend connected %sock
}

on *:SOCKOPEN:filesend.*:{
  if ($sockerr) {
    fs.echo $sockname Unable to connect ( $+ $sock($sockname).wsmsg $+ )
    .signal filesend error sockopen $sockname $sock($sockname).wsmsg
    .timer -o 1 0 fs.sockerr $sockname
    return
  }
;  .signal filesend connected $sockname
  fs.echo $sockname Connected
}

on *:SOCKREAD:filesend.*:{
  var %s = $sockname
  if ($sockerr) {
    fs.echo %s Sockread error
    .timer -o 1 0 fs.sockerr %s
    return
  }
  while (1) {
    if ($hget(filesend,protocol.err. $+ %s)) { return }
    if ($hget(filesend,dl.data. $+ %s)) && ($sock(%s).mark === Accepted) {
      sockread $hget(filesend,dl.data.bytesleft. $+ %s) &fs
      if ($sockbr == 0) { break }
      hdec filesend dl.data.bytesleft. $+ %s $sockbr
      .fwrite -b filesend.dl. $+ %s &fs
      var %id = $hget(filesend,dl.data.id. $+ %s) , %bl = $hget(filesend,dl.data.bytesleft. $+ %s)
      .signal filesend.getfile %s %id %bl $sockbr
      if (%bl <= 0) {
        var %path = $fopen(filesend.dl. $+ %s).fname , %f = $nopath(%path) , %size = $hget(filesend,dl.data.size. $+ %s)
        hdel filesend dl.data.id. $+ %s
        hdel filesend dl.data.bytesleft. $+ %s
        hdel filesend dl.data.size. $+ %s
        hdel filesend dl.data. $+ %s
        .fclose filesend.dl. $+ %s
        if ($file(%path).size !== %size) {
          hinc filesend $+(dl.data.requested.,%id,.,%s)
          var %req = $hget(filesend,$+(dl.data.requested.,%id,.,%s)) , %r.f = $hget(filesend,retry.file)
          .signal filesend getfile.err %s %id %req %r.f %f
          if (%req <= %r.f) {
            fs.echo %s Received corrupt file %f (auto-retry triggered %req $+ / $+ %r.f $+ )
            fs.queue %s -n rf %id
          }
          else {
            fs.echo %s Received corrupt file %f (no more auto-retry)
            hdel filesend $+(dl.data.requested.,%id,.,%s)
          }
        }
        else {
          hdel filesend $+(dl.data.requested.,%id,.,%s)
          fs.echo %s Received %f
          .signal filesend getfile.done %s %id %f
        }
      }
    }
    else {
      var %read
      sockread %read
      if ($sockbr > 800) {
        hadd filesend protocol.err. $+ %s 1
        fs.echo %s Disconnecting: string too large
        .timer -o 1 0 filesend.sockclose %s
        .signal -n filesend quiting %s
      }
      if ($sockbr == 0) { break }
      tokenize 32 %read
;      fs.echo %s Socktext: $1-
      if ($regex($1-,/^passrequest ([0-9a-z]){30}$/i)) && (%s == filesend.client) {
        fs.echo %s Password is requested by the server
;        .signal filesend pw.req %s
        sockwrite -n %s Password $md5($hget(filesend,pw.filesend.client) $2)
      }
      elseif (passaccept * iswm $1-) && (%s == filesend.client) {
        fs.echo %s Password accepted by the server
;        .signal filesend pw.accept %s
        sockwrite -n %s Version $filesend.version
        if ($left($2-,4) !=== $left($filesend.version,4)) {
          fs.echo %s Different version, disconnecting
          .signal filesend version.denied %s $2-
          filesend.sockclose %s
          return
        }
        sockmark %s Passaccept
      }
      elseif (passdenied == $1-) && (%s == filesend.client) {
        fs.echo %s Password denied by the server
        .signal filesend pw.denied %s
        filesend.sockclose %s
        return
      }
      elseif (versionaccept == $1-) && (%s == filesend.client) && ($sock(%s).mark === Passaccept) {
        sockmark %s Accepted
        .signal filesend version.accept %s
        fs.echo %s Version accepted
        fs.queue %s -n rl
      }
      elseif ($regex($1-,/^(?i)password(?-i) ([0-9a-f]){32}$/)) && (%s !== filesend.client) {
        if ($2 !=== $hget(filesend,md5pw. $+ %s)) {
          hdel filesend md5pw. $+ %s
          fs.echo %s Bad password received, closing connection
;          .signal filesend pw.bad %s
          sockwrite -n %s Passdenied
          filesend.sockclose %s
          return
        }
        hdel filesend md5pw. $+ %s
        sockmark %s Passaccept
        fs.echo %s Correct password received
;        .signal filesend pw.correct %s
        sockwrite -n %s Passaccept $filesend.version
      }
      elseif (version * iswm $1-) && (%s !== filesend.client) && ($sock(%s).mark === Passaccept) {
        if ($left($2-,4) !=== $left($filesend.version,4)) {
          .signal filesend version.denied %s $2-
          fs.echo %s Different version, disconnecting
          filesend.sockclose %s
          return
        }
        .signal filesend version.accept %s
        fs.echo %s Version accepted
        sockmark %s Accepted
        sockwrite -n %s Versionaccept
        fs.queue %s -n rl
      }
      elseif (requestList == $1-) && ($sock(%s).mark === Accepted) {
;          .signal filesend reqlist %s
        fs.queue %s -d sl
      }
      elseif ($(list & *) iswm $1-) && ($sock(%s).mark === Accepted) {
        .signal filesend getlist %s $2-
        if ($2 == 0) { fs.echo %s Listing $3 files }
        else { fs.echo %s FileID $2 -- Size $3 bytes -- Name $4- }
      }
      elseif ($(requestfile &) iswm $1-) && ($sock(%s).mark === Accepted) {
        if ($hget(fs.flist,$2) !== $null) {
;          .signal filesend reqfile %s $2
          fs.queue %s -d sf $2
        }
      }
      elseif ($(file & & *) iswm $1-) && ($sock(%s).mark === Accepted) {
        if ($numtok($4-,46) > 1) { var %file = $+($hget(filesend,dl.folder),\,$deltok($4-,-1,46)) , %type = . $+ $gettok($4-,-1,46) }
        else { var %file = $+($hget(filesend,dl.folder),\,$4-) , %type }
        var %f = %file $+ %type , %i = 1
        while ($isfile(%f)) {
          var %f = %file $+ ( $+ %i $+ ) $+ %type
          inc %i
        }
        var %file = $nopath(%f)
        if ($3 == -1) {
          fs.echo %s Receiving %file failed, file does not exist anymore.
          .signal filesend getfile.missing %s $2 $3 %file
          break
        }
        fs.echo %s Receiving %file ( $+ $3 bytes)
        .signal filesend getfile.start %s $2 $3 %file
        if ($fopen(filesend.dl. $+ %s)) { .fclose filesend.dl. $+ %s }
        .fopen -no filesend.dl. $+ %s $qt(%f)
        if ($3 <= 0) {
          .fclose filesend.dl. $+ %s
          if ($file(%f).size !== 0) {
            hinc filesend $+(dl.data.requested.,$2,.,%s)
            var %req = $hget(filesend,$+(dl.data.requested.,$2,.,%s)) , %r.f = $hget(filesend,retry.file)
            .signal filesend getfile.err %s $2 %req %r.f %file
            if (%req <= %r.f) {
              fs.echo %s Received corrupt file %file (auto-retry triggered %req $+ / $+ %r.f $+ )
              fs.queue %s -n rf $2
            }
            else {
              fs.echo %s Received corrupt file %file (no more auto-retry)
              hdel filesend $+(dl.data.requested.,$2,.,%s)
            }
          }
          else {
            fs.echo %s Received %file
            hdel filesend $+(dl.data.requested.,$2,.,%s)
            .signal filesend getfile.done %s $2 %file
          }
        }
        else {
          hadd filesend dl.data.id. $+ %s $2
          hadd filesend dl.data.bytesleft. $+ %s $3
          hadd filesend dl.data.size. $+ %s $3
          hadd filesend dl.data. $+ %s 1
        }
        
      }
      elseif (quiting == $1-) {
        .timer -o 1 0 filesend.sockclose %s
        fs.echo %s Quiting..
        .signal -n filesend quiting %s
        return
      }
      else {
        hadd filesend protocol.err. $+ %s 1
        fs.echo %s Disconnecting: Unknown socktext ( $+ $1- $+ )
        .timer -o 1 0 filesend.sockclose %s
        .signal -n filesend quiting %s
        return
      }
    }
  }
}

alias -l fs.queue {
; $1 = $sockname   $2 = -n/-d (next default)   $3- = item
  if ($sock($1).status !== active) { fs.echo $1 Socket is not connected | return }
  if ($len($hget(filesend,ul.queue. $+ $1) $hget(filesend,ul.queue.sf. $+ $1)) > 850) { fs.echo -e $1 Queue too large | return }
  if ($2 == -d) {
    if ($3 == sf) { var %q1 = $hget(filesend,ul.queue. $+ $1) , %q2 = $addtok($hget(filesend,ul.queue.sf. $+ $1),$3-,44) }
    else { var %q1 = $addtok($hget(filesend,ul.queue. $+ $1),$3-,44) , %q2 = $hget(filesend,ul.queue.sf. $+ $1) }
  }
  elseif ($2 == -n) {
    if ($3 == sf) { var %q1 = $hget(filesend,ul.queue. $+ $1) , %q2 = $instok($remtok($hget(filesend,ul.queue.sf. $+ $1),$3-,1,44),$3-,1,44) }
    else { var %q1 = $instok($remtok($hget(filesend,ul.queue. $+ $1),$3-,1,44),$3-,1,44) , %q2 = $hget(filesend,ul.queue.sf. $+ $1) }
  }
  else { var %q1 = $hget(filesend,ul.queue. $+ $1) , %q2 = $hget(filesend,ul.queue.sf. $+ $1) }
  var %q = $addtok(%q1,%q2,44)
  fs.echo $1 Qeueu %q
  hadd filesend ul.queue. $+ $1 %q1
  hadd filesend ul.queue.sf. $+ $1 %q2
  if ((%q == $3-) || (($2 == $null) && (%q !== $null))) && (!$hget(filesend,ul.status. $+ $1)) {
    var %next = $gettok(%q,1,44)
    if ($gettok(%next,1,32) == rf) {
      hadd filesend ul.status. $+ $1 requesting
      sockwrite -n $1 RequestFile $gettok(%next,2,32)
      .signal filesend requestedfile $1 $gettok(%next,2,32)
    }
    elseif (%next == rl) {
      hadd filesend ul.status. $+ $1 requesting
      sockwrite -n $1 RequestList
      .signal filesend requestedlist $1
    }
    elseif (%next == sl) {
      hadd filesend ul.listing. $+ $1 $hget(filesend,files)
      sockwrite -n $1 List 0 $hget(filesend,files)
      hadd filesend ul.status. $+ $1 listing
      .signal filesend sendlist $1
    }
    elseif ($gettok(%next,1,32) == sf) {
      var %id = $gettok(%next,2,32) , %f = $hget(fs.flist,%id)
      if (!$isfile(%f)) {
        hadd filesend ul.status. $+ $1 sending err
        sockwrite -n $1 File %id -1 $nopath(%f)
        fs.echo $1 Can't send file $qt(%f) $+ , file doesn't exist.
        .signal filesend sendfile.missing $1 %id
        return
      }
      if ($fopen(filesend.ul. $+ $1)) { .fclose filesend.ul. $+ $1 }
      .fopen filesend.ul. $+ $1 $qt(%f)
      hadd filesend ul.status. $+ $1 sending
      sockwrite -n $1 File %id $file(%f).size $nopath(%f)
      fs.echo $1 Sending requested file $nopath(%f) ( $+ $file(%f).size bytes)
      .signal filesend sendfile.start $1 %id
    }
    elseif (%next == q) {
      hadd filesend ul.status. $+ $1 requesting
      sockwrite -n $1 Quiting
    }
  }
  .signal filesend queue $1 $iif($hget(filesend,ul.status. $+ $1) == $null,idle,$gettok($v1,1,32)) %q
}

alias -l fs.list {
  var %i = $hget(filesend,ul.listing. $+ $1)
  if (!%i) {
    hdel filesend ul.listing. $+ $1
    hadd filesend ul.queue. $+ $1 $remtok($hget(filesend,ul.queue. $+ $1),sl,1,44)
    hdel filesend ul.status. $+ $1
    fs.queue $1
    return
  }
  var %id = $hget(fs.flist,%i).item , %f = $hget(fs.flist,%id)
  sockwrite -n $1 List %id $iif($isfile(%f),$file(%f).size,-1) $nopath(%f)
  dec %i
  hadd filesend ul.listing. $+ $1 %i
}

alias -l fs.send {
  var %bf = $calc(16384 - $sock($1).sq)
  if (%bf > 0) {
    var %br = $fread(filesend.ul. $+ $1,%bf,&fs)
  }
  if ($feof) {
    var %f = $fopen(filesend.ul. $+ $1).fname
    .fclose filesend.ul. $+ $1
    hadd filesend ul.queue.sf. $+ $1 $deltok($hget(filesend,ul.queue.sf. $+ $1),1,44)
    hdel filesend ul.status. $+ $1
    fs.echo $1 Done sending $nopath(%f)
    .signal filesend sendfile.done $1 %f
    fs.queue $1
  }
  elseif (%br > 0) {
    sockwrite -b $1 %br &fs
    .signal filesend.sendfile $1 $fopen(filesend.ul. $+ $1).pos %br
  }
}

on *:SOCKWRITE:filesend.*:{
  if ($sockerr) {
    fs.echo $sockname Sockwrite error
    .timer -o 1 0 fs.sockerr $sockname
    return
  }
  if ($sock($sockname).mark === Accepted) {
    var %st = $hget(filesend,ul.status. $+ $sockname)
    if (%st == sending) { fs.send $sockname }
    elseif (%st == listing) { fs.list $sockname }
    elseif (%st == sending err) {
      hdel filesend ul.status. $+ $sockname
      hadd filesend ul.queue.sf. $+ $sockname $deltok($hget(filesend,ul.queue.sf. $+ $sockname),1,44)
      fs.queue $sockname
    }
    elseif (%st == requesting) {
      hdel filesend ul.status. $+ $sockname
      hadd filesend ul.queue. $+ $sockname $deltok($hget(filesend,ul.queue. $+ $sockname),1,44)
      fs.queue $sockname
    }
    else { fs.queue $sockname }
  }
}

on *:SOCKCLOSE:filesend.*:{
  fs.echo $sockname Disconnected
  .timer -o 1 0 filesend.sockclose $sockname
}

alias -l fs.sockerr {
  if (!$hget(filesend)) { return }
  if ($1 == filesend.client) {
    hinc -u60 filesend sockerr. $+ $1
    if ($hget(filesend,sockerr. $+ $1) isnum 1 - $hget(filesend,retry.con. $+ $1)) {
      hdel filesend dl.data. $+ $1
      fs.echo Reconnecting $1
      .signal filesend error reconnect $1 $hget(filesend,sockerr. $+ $1) $hget(filesend,retry.con. $+ $1)
      if ($sock($1)) {
        fs.echo Socketname $1 is not free
        .timer -o 1 0 fs.sockerr $1
        return
      }
      sockopen filesend.client $hget(filesend,ip. $+ $1) $hget(filesend,port. $+ $1)
      if ($sockerr) {
        fs.echo $1 Sockopen error
        .timer -o 1 0 fs.sockerr $1
        return
      }
    }
    else { .timer -o 1 0 filesend.sockclose $1 }
  }
  else { .timer -o 1 0 filesend.sockclose $1 }
}

alias filesend.sockclose.msg { fs.queue $1 -n q }

alias filesend.sockclose {
  if ($sock($1)) { sockclose $1 }
  if ($hget(filesend)) {
    hdel filesend dl.data. $+ $1
    .signal filesend disconnected $1
    if ($fopen(filesend.dl. $+ $1)) { .fclose $v1 }
    if ($fopen(filesend.ul. $+ $1)) { .fclose $v1 }
    if (!$dialog(filesend)) { hdel -w filesend *. $+ $1 }
  }
  if ($1 == filesend.client) { .timer -o 1 0 fs.client.closed }
  else { .timer -o 1 0 fs.server.closed }
}

alias -l fs.server.closed {
  if (!$sock(filesend.server.*)) && (!$sock(filesend.listen)) {
    fs.echo filesend.server stopped
    .signal filesend server.close
    if ($dialog(filesend)) { return }
    if (!$sock(filesend.*)) {
      if ($hget(fs.flist)) { hfree fs.flist }
      if ($hget(filesend)) { hfree filesend }
    }
    elseif ($hget(filesend)) {
      hdel -w filesend *.filesend.server.*
      hdel -w filesend *.filesend.listen
    }
  }
}

alias -l fs.client.closed {
  fs.echo filesend.client stopped
  .signal filesend client.close filesend.client
  if (!$dialog(filesend)) {
    if (!$sock(filesend.*)) {
      if ($hget(fs.flist)) { hfree fs.flist }
      if ($hget(filesend)) { hfree filesend }
    }
    elseif ($hget(filesend)) { hdel -w filesend *.filesend.client }
  }
}

alias filesend.version { return v1.100 }

CTCP *:Filesend version:*:{ ctcp $nick Filesend versionreply $filesend.version | .ignore -tu5 $nick 1 }

alias -l fs.pwgen {
  var %i = $numtok($2,32)
  while (%i) {
    var %t = $gettok($2,%i,32)
    if ($len(%t) == 3) {
      var %a1 = $asc($left(%t,1)) , %a2 = $asc($right(%t,1))
      var %j = $iif(%a1 < %a2,%a1,%a2) , %max = $iif(%a1 < %a2,%a2,%a1)
      while (%j <= %max) {
        var %c = %c $+ $chr(%j)
        inc %j
      }
    }
    dec %i
  }
  var %i = $1 , %l = $len(%c)
  while (%i) {
    var %pw = %pw $+ $mid(%c,$rand(1,%l),1)
    dec %i
  }
  return %pw
}

alias -l makedir {
  ; $makedir(dir)
  ; makes a dir, even if the path doesn't exist yet.
  ; returns $true if succeeded, returns $false if failed.
  var %i = 1, %n = 0, %dir = $replace($noqt($1),/,\)
  while ($pos(%dir,\,%i) || $len(%dir) > %n) {
    var %n = $v1
    if (!$isdir($mid(%dir,1,%n))) mkdir $qt($mid(%dir,1,%n))
    inc %i
  }
  return $isdir($1)
  :error
  reseterror
  return $false
}