/*
 * tinyurlfuckery an xoc production
 * written by lazy-xo of xoc
 * uploads and downloads filez from tinyurl.com
 * 
 * http://xoc-staff.com/files/
 * http://cubicidal.net/files/
 *
 * tinyurl.com has a limit of about 50,000 characters per url.
 * this program encodes a file into base64 chunks that are
 * designed to come to a size of 45,000 characters on tinyurl.
 * it supplies these chunks to tinyurl as urls and saves the references
 * to a file, then supplies that file as a url - this program
 * uses that one as an index to the rest. the indexing coded here is only one
 * level deep, so forget any thoughts of backing up your 300gb pr0n
 * collection at tinyurl's expense... but anything a couple hundred
 * megs in size should be fine.
 * 
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

char mime[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

char right2bits(char ch) {
	ch = ch & 3;
	ch <<= 4;
	return ch;
	}

char right4bits(char ch) {
	ch = ch & 15;
	ch <<= 2;
	return ch;
	}

char right6bits(char ch) {
	ch = ch & 63;
	return ch;
	}

char conv2char(char ch) {
	ch=mime[ch];
	return ch;
	}

unsigned char char2num(char * ch) {
	return (unsigned char)(strstr(mime, ch) - (&mime[0]));
	}

void base64dump(char * srcfile) {
	int readfile = open(srcfile,O_RDONLY);

	char cha[1],chb[1],chc[1];
	char output[4];

	int dstfilenum=0;
	char dstfile[10]; bzero(dstfile, 10);
	sprintf(dstfile, "%d", dstfilenum);
	int writefile = open(dstfile,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);

	int count=0; int count2=0;
	while(1) {
		count += 4;;
		if(!read(readfile,cha,1)) {
			break;
			}

		if(!read(readfile,chb,1)) {
			output[0] = conv2char(((cha[0] >> 2) & 63));
			output[1] = conv2char((right2bits(cha[0])));
			output[2] = conv2char(64);
			output[3] = conv2char(64);
			write(writefile,output,4);
			break;
			}

		else {
			output[0] = conv2char(((cha[0] >> 2) & 63));
			output[1] = conv2char((right2bits(cha[0]) + ((chb[0] >> 4) & 15)));
			}

		if(!read(readfile,chc,1)) {
			output[2] = conv2char((right4bits(chb[0])));
			output[3] = conv2char(64);
			write(writefile,output,4);
			break;
			}

		else {
			output[2] = conv2char((right4bits(chb[0])) + ((chc[0] >> 6) & 3));
			output[3] = conv2char(right6bits(chc[0]));
			}
		write(writefile,output,4);
		if(output[0] == 0x2F || output[0] == 0x2B || output[0] == 0x3D) count += 2;
		if(output[1] == 0x2F || output[1] == 0x2B || output[1] == 0x3D) count += 2;
		if(output[2] == 0x2F || output[2] == 0x2B || output[2] == 0x3D) count += 2;
		if(output[3] == 0x2F || output[3] == 0x2B || output[3] == 0x3D) count += 2;
		if(count%45000 < 20 && count > 10000) {
			if(count2 == 0) {
				if(dstfilenum > 9000) {
					printf("Be nice.\n");
					exit(0);
					}
				close(writefile);
				dstfilenum++;
				sprintf(dstfile, "%d", dstfilenum);
				writefile = open(dstfile,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
				count2 = 1;
				}
			}
		else count2 = 0;
		}
	close(writefile);
	close(readfile);
	}

int onetwo(int readfile) {
	char cha[1];
	if(read(readfile,cha,1)) {
		if(cha[0] == mime[64]) return 2;
		}
	else return 1;
	}

void decodebase64(char * srcfile, char * dstfile) {
	int readfile = open(srcfile, O_RDONLY);

	unsigned char cha[2],chb[2],chc[2],chd[2];
	unsigned char output[3];

	int writefile = open(dstfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);

	int count=0;
	int btw=0;
	while(1) {
		count++;
		btw = 0;
		bzero(cha,2); bzero(chb,2); bzero(chc,2); bzero(chd,2);
		if(read(readfile,cha,1)) {
			while(cha[0] == '\n') {
				bzero(cha,2);
				read(readfile,cha,1);
				}
			output[0] = (char2num(cha) << 2);
			}
		else break;

		if(read(readfile,chb,1)) {
			while(chb[0] == '\n') {
				bzero(chb,2);
				read(readfile,chb,1);
				}
			output[0] = output[0] + (char2num(chb) >> 4);
			}
		else break;

		if(read(readfile,chc,1)) {
			while(chc[0] == '\n') {
				bzero(chc,2);
				read(readfile,chc,1);
				}
			if(chc[0] == mime[64]) {
				write(writefile,output,1);
				break;
				}
			output[1] = (char2num(chb) << 4) + (char2num(chc) >> 2);
			} 
		else break;
	
		if(read(readfile,chd,1)) {
			while(chd[0] == '\n') {
				bzero(chd,2);
				read(readfile,chd,1);
				}
			if(chd[0] == mime[64]) {
				write(writefile,output,2);
				break;
				}
			output[2] = ((char2num(chc) & 3) << 6) + char2num(chd);
			} 
		else break;
		write(writefile,output,3);
		}
	close(writefile);
	close(readfile);
	}

char *readline(int s) {
	char readbuf[2];

	char *line = (char *)malloc(12);
	bzero(line,12);
	int i=0; int status;

	for(i=0; i<11; i++) {
		status = read(s,readbuf,1);
		if(status == 0) return 0;
		line[i] = readbuf[0];
		}
	return line;
	}

int connectz0r(void) {
	struct hostent *h;
	sethostent(1);
	h = gethostbyname("tinyurl.com");
	endhostent();

	int s = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(80); 
	sin.sin_addr = (*(struct in_addr *)h->h_addr_list[0]);

	int c = connect(s,(struct sockaddr *)&sin,sizeof(struct sockaddr_in));
	if(c<0) {perror("connect go boom"); exit(1);}
	
	return s;
	}
		
int sendsize(char * srcfile) {
	int readfile = open(srcfile, O_RDONLY);
	int count=0;
	char buffer[2]; bzero(buffer, 2);
	while(read(readfile, buffer, 1)) {
		count++;
		if(buffer[0] == 0x2F || buffer[0] == 0x2B || buffer[0] == 0x3D) count += 2;
		bzero(buffer,2);
		}
	close(readfile);
	return count;
	}

char * postfile(char * srcfile, int s) {

	int filesize = sendsize(srcfile);
	filesize += 33;

	int readfile = open(srcfile, O_RDONLY);
	char buffer[2]; bzero(buffer, 2);

	write(s, "POST /create.php HTTP/1.1\r\n", 27);
	write(s, "Host: tinyurl.com\r\n", 19);
	write(s, "User-Agent: Jesus\r\n", 19);
	write(s, "Accept: */*\r\n", 13);
	write(s, "Accept-Language: en\r\n", 21);
	write(s, "Accept-Encoding: gzip,deflate\r\n", 31);
	write(s, "Accept-Charset: ISO-8859-1, utf-8\r\n", 35);
	write(s, "Keep-Alive: 300\r\n", 17);
	write(s, "Connection: keep-alive\r\n", 24);
	write(s, "Referer: http://tinyurl.com/create.php\r\n", 40);
	write(s, "Content-Type: application/x-www-form-urlencoded\r\n", 49);

	write(s, "Content-Length: ", 16);

	char size[100]; bzero(size, 100);
	sprintf(size, "%d", filesize);

	write(s, size, strlen(size));
	write(s, "\r\n\r\n", 4);

	write(s, "url=%3F", 7);

	while(read(readfile, buffer, 1)) {
		if(buffer[0] == 0x2F) write(s, "%2F", 3);
		else if(buffer[0] == 0x2B) write(s, "%2B", 3);
		else if(buffer[0] == 0x3D) write(s, "%3D", 3);
		else write(s, buffer, 1);
		bzero(buffer, 2);
		}
	close(readfile);

	write(s, "%3F&submit=Make+TinyURL%21", 26); 

	char * gibberish = "Ha!";
	int count = 0;
	while(count < (filesize/10)) {
		gibberish = readline(s);
		free(gibberish);
		count++;
		}
	
	char * massive;
	massive = malloc(10000);
	bzero(massive, 10000);
	count = 0;
	while(count < 10000) {
		read(s, buffer, 1);
		massive[count] = buffer[0];
		count++;
		}
	char * extension; extension = malloc(10); bzero(extension, 10);
	if(strstr(massive, "<b>http://tinyurl.com/") != NULL) {
		snprintf(extension, 6, "%s", (strstr(massive, "<b>http://tinyurl.com/") + 22));
		}
	free(massive);
	close(s);
	close(readfile);
	return extension;
	}

void getfile(char * srclink, char * dstfile, int s) {
	
	write(s, "GET /", 5);
	write(s, srclink, strlen(srclink));
	write(s, " HTTP/1.0\r\n", 11);
	write(s, "User-Agent: Jesus\r\n", 19);
	write(s, "Accept: */*\r\n", 13);
	write(s, "Host: tinyurl.com\r\n", 19);
	write(s, "Connection: Keep-Alive\r\n\r\n", 26);

	int writefile = open(dstfile,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);

	char * gibberish = "Ha!";
	int writeit = 0;
	while(gibberish > 0) {
		gibberish = readline(s);
		if(strstr(gibberish, "?") != NULL) {
			if(writeit == 0) {
				write(writefile, (strstr(gibberish, "?") + 1), strlen(strstr(gibberish, "?") + 1) );
				writeit = 1;
				}	
			else if(writeit == 1) {
				write(writefile, gibberish, (int)(strstr(gibberish, "?") - gibberish));
				close(s);
				close(writefile);
				return;
				}
			}
		else if(writeit == 1) {
			write(writefile, gibberish, strlen(gibberish));
			}
		free(gibberish);
		}
	}

void mergefiles(void) {
	int num=0;
	int afile;
	char buffer[2]; bzero(buffer, 2);
	char * numz; numz = malloc(10); bzero(numz, 10);
	int mergedfile = open("output", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);

	do {
		sprintf(numz, "%d", num);
		afile = open(numz, O_RDONLY);
		if(afile > 0) {
			while(read(afile, buffer, 1)) {
				write(mergedfile, buffer, 1);
				bzero(buffer, 2);
				}
			close(afile);
			unlink(numz);
			}
		num++;
		} while(afile > 0);
	}

void getallfiles(char * srclink) {
        int num=0;
        char * numz; numz = malloc(10); bzero(numz, 10);
        char * extension; extension = malloc(10); bzero(extension, 10);

        getfile(srclink, "index", connectz0r());

	int totalfilez = sendsize("index");
	totalfilez /= 5;

        int indexfile = open("index", O_RDONLY);

        while(read(indexfile, extension, 5)) {
		printf("%d%% down\n", ((100*num)/(totalfilez)));
                sprintf(numz, "%d", num);
                getfile(extension, numz, connectz0r());
                num++;
                }

	printf("download complete.\n");

	mergefiles();
        }

int numfilez(void) {
	int num=0;
	char numz[10]; bzero(numz, 10);
	int total=0; int status=0;
	do {
		sprintf(numz, "%d", num);
		status = open(numz, O_RDONLY);
		if(status > 0) total++;
		num++;
		} while(status > 0);
	return total;
	}

void postallfiles(void) {
	int num=0; char numz[10]; bzero(numz, 10);
	int status;
	char * extension;
	int indexfile = open("index", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
	int totalfilez = numfilez();
	do {
		printf("%d%% up\n", ((100*num)/(totalfilez)));
		sprintf(numz, "%d", num);
		status = open(numz, O_RDONLY);
		if(status > 0) {
			close(status);
			extension = postfile(numz, connectz0r());
			write(indexfile, extension, 5);
			free(extension);
			unlink(numz);
			}
		num++;
		} while(status > 0);
	close(indexfile);
	extension = postfile("index", connectz0r());
	printf("index: %s\n", extension);
	free(extension);
	}

int main(int argc, char * argv[]) {

	if(argc == 4 && !strncmp(argv[1], "-g",2)) {
		getallfiles(argv[2]);
		printf("decoding...\n");
		decodebase64("output", argv[3]);
		printf("decode complete.\n");
		unlink("index");
		unlink("output");
		}
	else if(argc == 3 && !strncmp(argv[1], "-p",2)) {
		printf("encoding...\n");
		base64dump(argv[2]);
		printf("encoding complete.\n");
		postallfiles();
		unlink("index");
		}
	else {
		printf("-p file_name\n");
		printf("-g link_extension file_name\n");
		}

	}
