#!/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 [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 = ; 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/, ); 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; }