###################################################################################### # fserve.irc # `butane (raffi@hick.org), requires jIRCii (v 6.18.05) #################################################################### JAY-EYE-ARE-CEE 2 # /load fserve.irc within jircii # # fserve.irc is a basic mIRC-like file server script for the irc client jIRCii. # if you don't have jIRCii you can obtain a copy at the following website: # # http://jircii.hick.org/ <- primary site # http://jircii.leenux.net/ <- backup site # # basically this script provides jIRCii with the same barebones fserve implementation # that mIRC has. if you want like a Hawkee Pro fserve you or someone else will have # to script it. the basic syntax of the fserve command is: # # /fserve [max gets] [welcome file] # # Typing /fserve by itself shows who is connected to your fserve and other fun info # An fserve session can be closed by typing: /fserve close # # a really simple fserve script would look like this: # # on public # { # if ($1 eq "!trigger") # { # call("/fserve $nick c:\mystuff\ 3 c:\mystuff\welcome.txt"); # } # } # # with the above script, whenever someone types !trigger in a channel, an fserve will # be launched to c:\mystuff, the user will be allowed to download a max of 3 files, and # the file c:\mystuff\welcome.txt will be displayed to them when they connect. # #-------------------------------------[ Info for Scripters ]---------------------------- # # this fserve addon is fully scriptable. if a user has this script loaded it is the same # as having a basic fserve hardcoded into the client. this means you as a scripter can # write addons that use this fserve as a base. # # == events == # # fserve_open # called when the fserve session starts # available: $this, $nick, $host # # fserve_error # called when an error occurs with the fserve # available: $this, $nick, $1- (for the error) # # fserve_close # called when the fserve session closes # # fserve # called when the connected user sends something t othe fserve # available: $this, $nick, $1- (for the text sent) # # * note that $this needs to be resolved to an fserve session using getFserveSession($this) # # == sets == # # FSERVE_CLOSE # FSERVE_ERROR # FSERVE_OPEN # FSERVE_REQUEST # # == settings (stored in jirc.prop) == # # fserve.maxgets (default: 3) # default maximum gets for an fserve session # # fserve.maxidle (default: 3 minutes) # maximum allowed idle time for a session, 0 = no max idle time at all # # == functions == # # closefserve($fserve, "reason") # closes the specified fserve session and fires an fserve_close # event with the specified reason. # # fserveSessions() # returns an @array of all fserve session variables # # getFserveSession($this) # resolves a $this variable to an fserve session variable ($fserve) # # sendf($fserve, "text") # sends the specified text to the socket of the specificed session # # == the fserve session variable == # # [$fserve variable] # retrieves information from the session $fserve, where variable is: # connected - 1 if this connection is open, 0 otherwise... # cwd - the current working directory for the user # gets - the number of gets the user has remaning # handle - socket $handle of the fserve session # idle - the number of seconds the user has been idle # nick - users nickname # root - the root directory of the fserve session # rwd - the real working directory of the session # # example: # # $idle = [$fserve idle]; # $idle is now the idle time of the session $fserve # # the fserve session variable also has several commands associated with it: # # [$fserve cd: "desired directory"] # changes the cwd of the session based on the specified desired # directory. returns 1 if the change was successful, 0 otherwise. # [$fserve decget] # decrements the allowed get counter # [$fserve file: "filename"] # converts "filename" to an acceptable filename + path based on the # real working directory (rwd) and the operating system # [$fserve ls] # returns an @array file list of the current working directory # [$fserve set: "key", "value"] # creates a new key within this fserve with the specified value # [$fserve touch] # resets the idle timer for this session # # # fserve sets # set FSERVE_OPEN { return "$nnn Established an fserve connection with $nick"; } set FSERVE_CLOSE { return "$nnn Fserve connection with $nick closed: $1-"; } set FSERVE_ERROR { return "$nnn Error establishing fserve connection with $nick $+ : $1-"; } set FSERVE_REQUEST { return "$nnn Sent fserve session request to $nick"; } # # default fserve implementation # on fserve_error { echo(parseSet("FSERVE_ERROR", %localData)); } on fserve_close { echo(parseSet("FSERVE_CLOSE", %localData)); } on fserve_open { local('$fserve $handle $temp'); echo(parseSet("FSERVE_OPEN", %localData)); $fserve = getFserveConnection($this); [$fserve touch]; [$fserve set: "connected", 1]; if (-exists [$fserve welcome]) { $handle = openf([$fserve welcome]); foreach $temp (readAll($handle)) { sendf($fserve, $temp); } } else { sendf($fserve, "Welcome to the jIRCii file server $nick"); } sendf($fserve, "Use: cd dir exit get help ls pwd read"); sendf($fserve, "[\\]"); } on fserve { local('$fserve @files $size'); $fserve = getFserveConnection($this); [$fserve touch]; if ($1 eq "dir" || $1 eq "ls") { @files = [$fserve ls]; sendf($fserve, "[" . [$fserve cwd] . "]"); foreach $var (@files) { if ($2 eq "" || $2 iswm $var) { if (!-isDir [$fserve file: $var]) { $size = formatBytes(lof([$fserve file: $var])); sendf($fserve, "$[45]var $size"); } else { sendf($fserve, "$[45]var"); } } } sendf($fserve, "End of list."); } else if ($1 eq "about") { sendf($fserve, "== About fserve.irc =="); sendf($fserve, "This is a simple fserve script for the cross platform IRC client jIRCii"); sendf($fserve, "Both this script and jIRCii can be downloaded at http://jircii.hick.org/"); } else if ($1 eq "help") { sendf($fserve, "\bC\bommand \bD\bescription"); sendf($fserve, "\babout\b - information about this fserve script"); sendf($fserve, "\bcd\b [directory] - change directory, use .. to specify up one level"); sendf($fserve, "\bdir\b [*wildcard*] - retrieve a file listing, use *wildcard* to filter what is listed"); sendf($fserve, "\bexit\b - leave the fserve"); sendf($fserve, "\bget\b [file] - retrieves the specified file"); sendf($fserve, "\bgets\b - total number of file you're allowed to get"); sendf($fserve, "\bhelp\b - this help command :)"); sendf($fserve, "\bls\b [*wildcard*] - retrieve a file listing, use *wildcard* to filter what is listed"); sendf($fserve, "\bpwd\b - prints the current directory you are in"); sendf($fserve, "\bread\b [file] - dumps the specified file to this session"); } else if ($1 eq "gets") { if ([$fserve gets] == 0) { sendf($fserve, "You're not allocated to recieve any more files from this session"); } else { sendf($fserve, "You're allowed to get " . [$fserve gets] . iff([$fserve gets] > 1, " more files", "more file")); } } else if ($1 eq "get") { $f = [$fserve file: $2]; if ([$fserve gets] <= 0) { sendf($fserve, "I'm not allowed to send you any more files"); } else if ($2 ne "" && '..' !isin $2 && -exists $f) { sendf($fserve, "Sending you $2 which should be on its way shortly"); call("/dcc send $nick $f"); [$fserve decget]; } else { sendf($fserve, "Could not open $2 for sending"); } } else if ($1 eq "read") { $f = [$fserve file: $2]; if ($2 ne "" && '..' !isin $2 && -exists $f) { $handle = openf($f); foreach $temp (readAll($handle)) { sendf($fserve, $temp); } if (checkError($error)) { sendf($fserve, "Could not open $2 $+ : $error"); } } else { sendf($fserve, "Could not open $2 for reading"); } } else if ($1 eq "cwd" || $1 eq "pwd") { sendf($fserve, "[" . [$fserve cwd] . "]"); } else if ($1 eq "exit" || $1 eq "quit" || $1 eq "bye") { sendf($fserve, "Good bye $nick $+ !"); closefserve($fserve, "user left the session"); } else if ($1 eq "cd") { if ([$fserve cd: $2-]) { sendf($fserve, "[" . [$fserve cwd] . "]"); } else { sendf($fserve, "Could not change to $2- $+ : no such directory"); } } } # # The actual mucky muck that makes all of this possible (diehard sleep scripting here) # alias fserve { if ($1 eq "close") { foreach $temp (fserveSessions()) { if (lc([$temp nick]) eq lc($2)) { closefserve($temp, "/fserve close"); } } return; } if ($1 eq "") { local('$nick $idle $gets $cwd $temp'); echo("\bN\bick \bI\bdle \bG\bets \bC\burrent Directory "); foreach $temp (fserveSessions()) { if ([$temp connected]) { ($nick, $idle, $gets, $cwd) = array([$temp nick], formatTime2([$temp idle]), [$temp gets], [$temp rwd]); echo("\b $+ $[10]nick $+ \b $[6]idle $[4]gets $cwd"); } else { $nick = [$temp nick]; echo("\b $+ $[10]nick $+ \b waiting for user to accept chat..."); } } return; } local('$port $ip $c %INFO'); if (!-isDir $2) { echo("* Non-existant directory specified for fserve to $1 $+ : $2"); return; } $port = getNextPort(); $ip = longip(localip()); $c = chr(1); $socket = listen($port, 30 * 1000, $host, lambda(&_handle_connect, $nick => $1)); %INFO["nick"] = $1; %INFO["root"] = $2; %INFO["gets"] = iff($3 ne "", $3, getProperty("fserve.maxgets", 3)); %INFO["welcome"] = $4; %INFO["cwd"] = ""; %INFO["handle"] = $socket; %FSERVE[$socket] = lambda(&fserve_session, %INFO => %INFO); echo(parseSet("FSERVE_REQUEST", hash($nick => $1, $this => $socket))); sendRaw("PRIVMSG $1 : $+ $c $+ DCC CHAT Chat $ip $port $+ $c"); } sub getFserveConnection { return %FSERVE[$1]; } sub sendf { if ($2 ne $null) { println([$1 handle], $2); } } sub closefserve # closefserve($this, reason) { f_doClose($1, $2); f_doRemove($1); } sub fserveSessions { local('@rv $temp'); foreach $temp (%FSERVE) { push(@rv, %FSERVE[$temp]); } return @rv; } sub _handle_connect { if (checkError($error)) { fireEvent("fserve_error", hash($nick => $nick, $data => "$nick $error", $this => $1)); f_doRemove(%FSERVE[$1]); return; } fireEvent("fserve_open", hash($nick => $nick, $host => $host, $this => $1)); read($1, lambda(&_handle_read, $nick => $nick)); } sub _handle_read { fireEvent("fserve", hash($nick => $nick, $this => $1, $data => "$nick $2", $parms => $2)); } sub fserve_session { if ($0 eq "cwd") { return _cwd(%INFO); } else if ($0 eq "rwd") { return _rwd(%INFO); } else if ($0 eq "set") { %INFO[$1] = $2; } else if ($0 eq "touch") { %INFO["idle"] = ticks() / 1000; %INFO["warned"] = 0; } else if ($0 eq "idle") { return (ticks() / 1000) - %INFO["idle"]; } else if ($0 eq "decget") { %INFO["gets"] = %INFO["gets"] - 1; } else if ($0 eq "file") { return _gf(%INFO, $1); } else if ($0 eq "ls") { return _ls(_rwd(%INFO)); } else if ($0 eq "cd") { local('$old'); $old = %INFO['cwd']; %INFO['cwd'] = _modifyPath(%INFO, $1); if (-isDir _rwd(%INFO)) { return 1; } else { %INFO['cwd'] = $old; return 0; } } return %INFO[$0]; } # # Misc Functions # sub f_doClose { fireEvent("fserve_close", hash($nick => [$1 nick], $this => [$1 handle], $data => [$1 nick] . " $2", $parms => $2)); [$1 set: "connected", 0]; closef([$1 handle]); } sub f_doRemove { remove(%FSERVE, [$1 handle]); } sub f_idlecheck { local('$fserve %INFO $ctime $idle @kill $maxidle $warnidle'); $midle = getProperty("fserve.maxidle", 3); $widle = $midle - 1; $maxidle = $midle * 60; $warnidle = $maxidle - 60; foreach $key => $fserve (%FSERVE) { if ([$fserve connected] == 1) { if (-eof [$fserve handle]) { f_doClose($fserve, "connection closed"); push(@kill, $fserve); } else if ($midle > 0) { $idle = [$fserve idle]; if ($idle > $warnidle && $idle < $maxidle && [$fserve warned] == 0) { [$fserve set: "warned", 1]; sendf($fserve, "You have been idle for $widle minutes, would you like to stay connected?"); } else if ($idle > $maxidle) { sendf($fserve, "You have been idle for $midle minutes, closing the session"); f_doClose($fserve, "idle timeout"); push(@kill, $fserve); } } } } while (size(@kill) > 0) { f_doRemove(pop(@kill)); } } # # Utility functions (should only be called by the fserve_session closure) # sub _cwd { return strrep("\\" . $1['cwd'], '/', "\\"); } sub _rwd { return strrep($1['root'] . "/" . $1['cwd'], "\\", "/"); } sub _gf { $temp = getFileProper(_rwd($1), $2); return $temp; } sub _modifyPath { local('$path @paths @rv'); if (strlen($2) >= 1 && charAt($2, 0) eq "\\") { $1['cwd'] = $2; } else { $1['cwd'] = $1['cwd'] . "\\" . $2; } @paths = split('\\\\', _cwd($1)); # split a single \ in regex... sheesh :( foreach $temp (@paths) { if ($temp eq ".." && size(@rv) > 0) { pop(@rv); } else if ($temp ne $null && $temp ne "..") { push(@rv, $temp); } } return join("\\", @rv); } sub _ls { local('@dirs @files @data $temp'); @rv = array(); @data = ls(strrep($1, "\\", '/')); foreach $temp (@data) { if (-isDir $temp && !-isHidden $temp) { push(@dirs, getFileName($temp)); } if (-isFile $temp && !-isHidden $temp) { push(@files, getFileName($temp)); } } map({ push(@rv, $1); }, @dirs); map({ push(@rv, $1); }, @files); return @rv; } # # setup our idle check timer... # if ($_FTIMER ne "") { stopTimer($_FTIMER); } # in case of /reload $_FTIMER = addTimer(&f_idlecheck, 10 * 1000);