#!/usr/bin/perl
# Version 2.1.1 (13. July 2007)
# RapidShare AG OpenSource Perl Uploader V2 (with upload resume). For non-commercial use only. All rights reserved.
# Included: Uploading to free, collector's and premium-zone. The MD5-check after uploads checks if the upload worked.
# Upload resume can continue aborted downloads up to 24 hours after the download aborted. This means, incomplete files
# will automatically be deleted from the RapidShare servers 24 hours after the first chunk arrived.
# This is a PERL script written for experts and for coders wanting to know how to write own upload programs.
# Tested under Linux and Linux only.
# If you write your own upload-tools, please look at our rsapi.cgi calls. You need them to have fun.
#
# To upload a file, put this script on a machine with perl installed and use the following syntax:
# perl rsapi.pl free mytestfile.rar (this uploads mytestfile.rar as a free user)
# perl rsapi.pl prem archive.rar 334 test (this uploads archive.rar to the premium-zone of login 334 with password test)
# perl rsapi.pl col a.rar testuser mypw (this uploads a.rar to the collector's-zone of login testuser with password mypw)
use strict;
use warnings;
use Digest::MD5("md5_hex");
use Fcntl;
use IO::Socket;
my ($file, $zone, $login, $password, $uploadpath, $cursize, $size, $filecontent, $md5hex, $size2, $socket, $uploadserver, $killcode);
# This chapter sets some vars and parses some vars.
$/ = undef;
$SIG{PIPE} = 'IGNORE';
$file = $ARGV[0] || die "Syntax: $0 <filename to upload> <free|prem|col> [login] [password]\n";
$zone = $ARGV[1] || "";
$login = $ARGV[2] || "";
$password = $ARGV[3] || "";
$uploadpath = "l3";
$size = -s $file || die "File $file is empty or does not exist!\n";
# This chapter checks the file and calculates the MD5HEX of the existing local file.
print "File $file has $size bytes. Calculating MD5HEX...\n";
open(FH, $file) || die "Unable to open file: $!\n";
$filecontent = <FH>;
close(FH);
$md5hex = md5_hex($filecontent);
$size2 = length($filecontent);
print "MD5HEX is $md5hex ($size2 bytes analyzed)\n";
unless ($size == $size2) { die "Strange error: $size bytes found, but only $size2 bytes analyzed?\n" }
# This chapter finds out which upload server is free for uploading our file by fetching http://rapidshare.com/cgi-bin/rsapi.cgi?sub=nextuploadserver_v1
if ($login and $password) { print "Trying to upload to your $zone account.\n" } else { print "Uploading as a free user.\n" }
print "Getting upload server infos.\n";
$socket = IO::Socket::INET->new(PeerAddr => "rapidshare.com:80") || die "Unable to open port: $!\n";
print $socket qq|GET /cgi-bin/rsapi.cgi?sub=nextuploadserver_v1 HTTP/1.0\r\n\r\n|;
($uploadserver) = <$socket> =~ /\r\n\r\n(\d+)/;
unless ($uploadserver) { die "Uploadserver invalid? Internal error!\n" }
print "Uploading to rs$uploadserver$uploadpath.rapidshare.com\n";
$cursize = 0;
while ($cursize < $size) { $cursize = &uploadchunk($file, $md5hex, $size, $cursize, "rs$uploadserver$uploadpath.rapidshare.com:80") }
sub uploadchunk {
my $file = shift || die;
my $md5hex = shift || die;
my $size = shift || die;
my $cursize = shift || 0;
my $fulluploadserver = shift || die;
my ($uploaddata, $wantchunksize, $fh, $socket, $boundary, $contentheader, $contenttail, $contentlength, $header, $chunks, $chunksize,
$bufferlen, $buffer, $result, $fileid, $complete, $resumed, $filename);
if (-e "$file.uploaddata") {
print "Found .uploaddata! Overriding settings and trying to resume.\n";
open(I, "$file.uploaddata") or die "Unable to open file: $!\n";
($fulluploadserver, $fileid, $killcode) = split(/\n/, <I>);
print "Uploadserver=$fulluploadserver\nFile-ID=$fileid\nKillcode=$killcode\n";
close(I);
print "Checking if RS gives an OK and the position...\n";
$socket = IO::Socket::INET->new(PeerAddr => "rapidshare.com:80") || die "Unable to open port: $!\n";
print $socket qq|GET /cgi-bin/rsapi.cgi?sub=checkincomplete_v1&fileid=$fileid&killcode=$killcode HTTP/1.0\r\n\r\n|;
$result = <$socket>;
unless ($result =~ /\r\n\r\n(\d+)/) { die "I can't resume the file. Please delete $file.uploaddata. RS said:\n$result\n" }
$cursize = $1;
print "All ok. The upload stopped at $cursize. Trying to resume.\n";
$resumed = 1;
}
$wantchunksize = 1024000;
if ($size > $wantchunksize) {
$chunks = 1;
$chunksize = $size - $cursize;
if ($chunksize > $wantchunksize) { $chunksize = $wantchunksize } else { $complete = 1 }
} else {
$chunks = 0;
$chunksize = $size;
}
print "Upload chunk is $chunksize bytes starting at $cursize.\n";
sysopen($fh, $file, O_RDONLY) || die "Unable to open file: $!\n";
$filename = $file =~ /[\/\\]([^\/\\]+)$/ ? $1 : $file;
$socket = IO::Socket::INET->new(PeerAddr => $fulluploadserver) || die "Unable to open socket: $!\n";
$boundary = "---------------------632865735RS4EVER5675865";
$contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="rsapi_v1"\r\n\r\n1\r\n|;
if ($resumed) {
$contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="fileid"\r\n\r\n$fileid\r\n|;
$contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="killcode"\r\n\r\n$killcode\r\n|;
if ($complete) { $contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="complete"\r\n\r\n1\r\n| }
} else {
if ($zone eq "prem" and $login and $password) {
$contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="login"\r\n\r\n$login\r\n|;
$contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="password"\r\n\r\n$password\r\n|;
}
if ($zone eq "col" and $login and $password) {
$contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="freeaccountid"\r\n\r\n$login\r\n|;
$contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="password"\r\n\r\n$password\r\n|;
}
if ($chunks) { $contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="incomplete"\r\n\r\n1\r\n| }
}
$contentheader .= qq|$boundary\r\nContent-Disposition: form-data; name="filecontent"; filename="$filename"\r\n\r\n|;
$contenttail = "\r\n$boundary--\r\n";
$contentlength = length($contentheader) + $chunksize + length($contenttail);
if ($resumed) {
$header = qq|POST /cgi-bin/uploadresume.cgi HTTP/1.0\r\nContent-Type: multipart/form-data; boundary=$boundary\r\nContent-Length: $contentlength\r\n\r\n|;
} else {
$header = qq|POST /cgi-bin/upload.cgi HTTP/1.0\r\nContent-Type: multipart/form-data; boundary=$boundary\r\nContent-Length: $contentlength\r\n\r\n|;
}
print $socket "$header$contentheader";
sysseek($fh, $cursize, 0);
$bufferlen = sysread($fh, $buffer, $wantchunksize) || 0;
unless ($bufferlen) { die "Error while reading file: $!\n" }
print "Sending $bufferlen bytes.\n";
$cursize += $bufferlen;
print $socket $buffer;
print $socket $contenttail;
print "Server response:\n";
($result) = <$socket> =~ /\r\n\r\n(.+)/s;
unless ($result) { die "Ooops! Did not receive any valid server results?\n" }
print $result . "\n";
if ($resumed) {
if ($complete) {
if ($result =~ /^COMPLETE,(\w+)/) {
print "Upload completed! MD5HEX=$1 Checking MD5...\n";
if ($md5hex ne $1) { die "MD5-CHECK NOT PASSED! LOCAL=$md5hex REMOTE=$1\n" }
print "MD5-check passed. Upload OK! Saving status to rsapiuploads.txt\n";
open(O,">>rsapiuploads.txt") or die "Unable to save to rsapiuploads.txt: $!\n";
print O "Upload OK!\n\n";
close(O);
unlink("$file.uploaddata");
} else {
die "Unexpected server response!\n";
}
} else {
if ($result =~ /^CHUNK,(\d+)/) {
print "Chunk upload completed! Uploaded=$1\n";
} else {
die "Unexpected server response!\n";
}
}
} else {
if ($result =~ /files\/(\d+)/) { $fileid = $1 } else { die "Server result did not contain a file ID.\n" }
unless ($result =~ /File1\.3=(\d+)/ and $1 == $cursize) { die "Server did not save all data we sent.\n" }
unless ($result =~ /File1\.2=.+?killcode=(\d+)/) { die "Server did not send our killcode.\n" }
$killcode = $1;
open(O,">>rsapiuploads.txt") or die "Unable to save to rsapiuploads.txt: $!\n";
print O "Uploading $file. Download-links:\n$result";
close(O);
if ($chunks) {
open(O, ">$file.uploaddata") or die "Unable to save upload server: $!\n";
print O "$fulluploadserver\n$fileid\n$killcode\n";
close(O);
}
}
return $cursize;
}