⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mudftp.pl

📁 Unix下的MUD客户端程序
💻 PL
字号:
# mudFTP support - push mode only, no caching support yet, autologin supported## Oliver Jowett <icecube@ihug.co.nz>, 10/02/99package mudFTP;use Socket;use Fcntl;use POSIX qw(:sys_wait_h :errno_h);# some configurable bits$Temp = "/tmp/mudftp.";$IdleTimeout = 600;# internal vars$Editor = "";%Config = ();    $Filename = "";$LinesRead = 0;$LinesTotal = 0;$EditorFile = "";$EditString = "";$State = 'Disabled';$Buffer = "";$PID = -1;$AutoHost = 0;$AutoPort = 0;$AutoID = "";$HasSocket = 0;$IdleCount = 0;$thisAccount = "";$thisPW = "";$active = 0;sub Message {    &main::run ("#print mudFTP mudFTP: " . $_[0]);}sub SetState {    $State = $_[0];    Message("$State");}sub Shutdown {    if ($PID != -1) {        kill 15, $PID;        $PID = -1;        wait;    }    if ($EditorFile ne "") {        unlink($EditorFile);        $EditorFile = "";    }        if ($HasSocket) {        close(MUDFTP);        $HasSocket = 0;    }        $Buffer = "";}sub Error {    Message("ERROR: " . $_[0] . "\n");    SetState('Idle');    Shutdown();}sub SendCmd {    my $str = $_[0] . "\012";    my $nwrite = syswrite(MUDFTP, $str, length($str));    if (!defined($nwrite) || $nwrite != length($str)) {        Error("Command write error: $!");    }}    sub ReadConfig {    # read ~/.mudftp    SetState('Idle');        my $configfile = $main::ENV{HOME} . "/.mudftp";        if (!open (IN, $configfile)) {        Message("can't read $configfile: $!");        return;    }        while (<IN>) {        if (/^\s*mud\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) {            my @data = ($2, $3, $4, $5);            $Config{$1} = \@data;        } elsif (/^\s*editor\s+(.*)$/) {            $Editor = $1;        }    }    close(IN);    if ($Editor eq "") {        print "No editor defined, mudftp disabled.\n";        SetState('Disabled');    }}sub Connect {    # Connect to the current mud, turn on push mode    if ($HasSocket) {        Shutdown();    }        my ($host, $port);        if (exists($Config{$main::mud})) {        ($host, $port, $thisAccount, $thisPW) = @{$Config{$main::mud}};    } elsif ($AutoPort) {        $host = $AutoHost;        $port = $AutoPort;        $thisAccount = "*";        $thisPW = $AutoID;    } else {        Error("No config info for $main::mud");        return;    }    my $proto = getprotobyname('tcp');    my $ip = gethostbyname($host);    if (!$ip) {        Error("Unknown host: $host");        return 0;    }    my $paddr = sockaddr_in($port, $ip);    if (!socket(MUDFTP, PF_INET, SOCK_STREAM, $proto)) {        Error("Socket error: $!");        return 0;    }    $HasSocket = 1;        if (!fcntl(MUDFTP, F_SETFL, O_NONBLOCK)) {        Error("Fcntl error: $!");        return 0;    }                if (!connect(MUDFTP, $paddr)) {        if ($! != &EINPROGRESS) {            Error("connect error: $!");            return 0;        }    }    SetState('Connecting');}sub CheckCompleteRx {    # See if we're done receiving a file    if ($LinesRead == $LinesTotal) {        # Read complete. Create temp file, spawn editor        # bleh, perl has no tmpnam() equivalent?        $EditorFile = $Temp . $main::now . $$;        open(EDITFILE, ">$EditorFile") || do {            Error("Can't open $EditorFile: $!");            return;        };        print EDITFILE "$EditString";        close(EDITFILE) || do {            Error("Error writing to $EditorFile: $!");            return;        };        # spawn editor        my $cmdline = $Editor;        $cmdline =~ s/%/$EditorFile/g;        unless ($PID = fork()) {            # Child            exec($cmdline);            exit(255); # erk!        }        SetState('Waiting for editor');    }}sub Consume {    $Buffer =~ s/^(.*)\012//;    $active = 1;}sub Read {    while (1) {        my $nread = sysread(MUDFTP, $Buffer, 4096, length($Buffer));        if (!defined($nread)) {            if ($! != &EAGAIN) {                Error("read error: $!");            }            return;        }        if ($nread == 0) {            if (length($Buffer) == 0) {                Error("read error: EOF from server");            }            return;        }    }}sub BeginPut {    # Read and count lines    if (!open (IN, "<$EditorFile")) {        Error("Can't reopen edited file: $!");        return;    }    $EditString = "";    my $lines = 0;    while (<IN>) {        $lines++; $EditString .= $_;    }    close(IN);    # Is the last line unterminated?    if ($EditString !~ /\n$/) {        $EditString .= "\n";    }    unlink($EditorFile);    $EditorFile = "";        SendCmd("PUT $Filename $lines");    SetState('Sending file');    $active = 1;}sub PutFile {    while (1) {        my $nwrite = syswrite(MUDFTP, $EditString, length($EditString));        if (!defined($nwrite)) {            if ($! != &EAGAIN) {                Error("Write error: $!");            }            return;        }        if ($nwrite == 0) {            return 0;        }                if ($nwrite > 0) {            $EditString = substr($EditString, $nwrite);            $active = 1;        }        if ($EditString eq "") {            SetState('Waiting for server');        }    }}# Core FSM# arg0 = pending line (maybe undef)# arg1 = clear to write?sub UpdateFSM {    my ($line, $canwrite) = @_;        for ($State) {        /^Connecting/ && do {            if ($canwrite) {                SendCmd("$thisAccount $thisPW");                SetState('Authenticating');            }            last;        };        /^Authenticating/ && do {            if (defined($line)) {                Consume();  # eat the line                if ($line =~ /^OK/) {                    SendCmd("PUSH");                    SetState('Setting PUSH mode');                } else {                    Error("Authentication failed: " . $line);                }            }            last;        };        /^Setting PUSH mode/ && do {            if (defined($line)) {                Consume();  # eat the line                if ($line =~ /^OK/) {                    SetState('Waiting for requests');                } else {                    Error("Couldn't set push mode: " . $line);                }                $IdleCount = 0;            }            last;        };        /^Waiting for requests/ && do {            if (defined($line)) {                Consume();  # eat the line                if ($line =~ /^SENDING (\S+) (\d+) (\S+)$/) {                    $Filename = $1;                    $LinesTotal = $2;                    $Checksum = $3;                    $LinesRead = 0;                    $EditString = "";                    SetState('Reading request');                    CheckCompleteRx();                } else {                    Error("Unexpected request: " . $line);                }            } elsif ($IdleTimeout) {                $IdleCount++;                if ($IdleCount > $IdleTimeout) {                    $IdleCount = 0;                    SendCmd("NOOP");                    SetState('Waiting for keepalive');                }            }            last;        };        /^Waiting for keepalive/ && do {            if (defined($line)) {                if ($line =~ /^SENDING/) {                    # Oops, they sent us something just as we did a noop                    $IdleCount = -1;   # magic value                    SetState('Waiting for requests');                    $active = 1;                    last;                }                if ($line =~ /^OK/) {                    Consume();                    $IdleCount = 0;                    SetState('Waiting for requests');                    last;                }                Error("Keepalive no-op failed: $line");                last;            }            $IdleCount++;            if ($IdleCount > 60) {                Error("Server failed to respond to keepalive");            }                        last;        };                                        /^Reading request/ && do {            if (defined($line)) {                Consume();  # eat the line                $EditString .= $line . "\n";                $LinesRead++;                CheckCompleteRx();            }            last;        };        /^Waiting for editor/ && do {            my $died = waitpid($PID, WNOHANG);            if ($died > 0) {                # Editor exited                $PID = -1;                                if ($? != 0) {                    if (WIFEXITED($?)) {                        if (WEXITSTATUS($?) == 255) {                            $status = "(exec failed, editor not found?)";                        } else {                            $status = "with status " . WEXITSTATUS($?);                        }                                                } else {                        $status = "via signal " . WTERMSIG($?);                    }                                        Message("Editor exited $status");                    print "mudFTP: Editor exited $status\n"; # make sure the user sees this                    SendCmd("STOP");                    SetState('Waiting for server');                } else {                    # Read and send file                    BeginPut();                }            }            last;                        };        /^Sending file/ && do {            if ($canwrite) {                PutFile();   # keep going..            }            last;        };                /^Waiting for server/ && do {            if (defined($line)) {                # we're waiting for an OK / FAILED from the server after PUT/STOP                Consume();  # eat the line                                # Better check for keepalives here                if ($IdleCount == -1) {                    if ($line =~ /^OK/) {                        $IdleCount = 0;                        last; # do nothing for now                    }                    Error("Pending keepalive failed: $line");                    last;                }                                if ($line =~ /^OK/) {                    $IdleCount = 0;                    SetState('Waiting for requests');                } else {                    Error("Server rejected edit: " . $line);                }            }            last;        };        (/^Idle/ || /^Disabled/) && last;        Error("In unhandled state: $State");        last;    }}# Idle function, runs the FSMsub Idle {    my $canwrite = 0;        # See if we need to do a select    if ($HasSocket) {        my ($rin, $rout, $wout, $eout) = ("", "", "", "");        vec($rin, fileno(MUDFTP), 1) = 1;        if (select($rout=$rin, $wout=$rin, $eout=$rin, 0) > 0) {            # ok, we maybe have data etc            if (vec($rout, fileno(MUDFTP), 1)) {                Read();            }                        if ($HasSocket && vec($wout, fileno(MUDFTP), 1)) {                # Write                $canwrite = 1;            }                                  if ($HasSocket && vec($eout, fileno(MUDFTP), 1)) {                # Exception                Error("Exception status on mudftp socket");                            }        }    }    # Now call the fsm    do {        # see if we have a line to handle        my $nextline = undef;        ($Buffer =~ /^(.*)\012/) && ($nextline = $1);        $active = 0;                UpdateFSM($nextline, $canwrite);    } while ($active);}sub Detect {    if (/^mudFTP supported on ([^:]+):(\d+) \(token ([^)]+)\)$/) {        # Autologin support        $AutoHost = $1;        $AutoPort = $2;        $AutoID = $3;        Connect();    }            if (/^\S+\xE6$/) {        # mudftp pull mode                Connect();    }}&main::run("#window -w40 -h6 -x-41 -y3 -t5 mudFTP");&ReadConfig();&main::output_add(\&Detect);&main::callout_add(\&Idle, 1);&main::done_add(\&Shutdown);package main;sub cmd_mudftp {    &mudFTP::Connect();    return;}1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -