#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BANNER "HITBDaemon v.2.2 ready\r\n\r\n"
#define GREETING "EHLO "
#define QUIT "QUIT"
#ifndef BUFSIZ
#define BUFSIZ 256
#endif

void error(char *msg) {
    perror(msg);
    exit(1);
}

int socketr(int sd, char *buf) {

    bzero(buf, BUFSIZ);
    int pos = 0;
    char c = 0;
    while (pos < BUFSIZ && c!= 13) {
        read(sd, (char *)&c, 1);
        if (c != 13 && c!= 10) {
            buf[pos] = c;
            pos++;
            fprintf(stderr, "%c", c);
        }
    }
    fprintf(stderr, "\n");
    return pos;

}

char *read_file() {
    FILE *fp;
    static char flagstr[60];
    if ((fp = fopen("/home/daemon02/flag.txt", "r")) == NULL) {
	    printf("Cannot open flag file\n");
	    exit(1);
    } else {
	    fgets(flagstr, 60, fp);
    }
    fclose(fp);
    return flagstr;
}

socketw(int sd, const char *fmt, ...) {
    char buf[BUFSIZ + 1];
    va_list arg_ptr;
    
    va_start(arg_ptr, fmt);
    vsnprintf(buf, BUFSIZ, fmt, arg_ptr);
    write(sd, buf, strlen(buf));
    va_end(arg_ptr);


}

void handle_socket(int sd) {
    char msg[BUFSIZ+1];
    char *name;
    char greetz[BUFSIZ + 1];
    char *flagstr;

    flagstr = read_file();
    
    socketw(sd, BANNER);
    do {
        socketr(sd, msg);
        if (strncmp(msg, GREETING, strlen(GREETING))) {
            socketw(sd, "Don't know what is %s. polite people say EHLO first\r\n", msg);
        }
    } while (strncmp(msg, GREETING, strlen(GREETING)));
    socketw(sd, "EHLO %s. session activated. Flag ID: %s\r\n", (msg + strlen(GREETING)), flagstr); 
    name = strdup((char *)(msg + strlen(GREETING)));
    snprintf(greetz, BUFSIZ, "%s: %%s", name);
    fprintf(stderr, "greeting is %s\n", greetz);
    do {
        socketr(sd, msg);
        socketw(sd, greetz, "Uh uh..dont know what u say!\r\n");
    } while (strncmp(msg, QUIT, strlen(QUIT)));
    socketw(sd, "Bye bye %s", name);
    close(sd);
    exit(1);
}
            
int main(int argc, char *argv[]) 
{
    int sockfd, newsockfd, portno, clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n, on = 1;

    char *flagstr;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s port\n", argv[0]);
        exit(1);
    }

    flagstr = read_file();
    

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        error("Error opening socket");
    }
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    printf("Binding port %i\n", portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr,
                sizeof(serv_addr)) < 0)
        error("Error binding socket");

    printf("Network daemon started successefully\n");
    /*
     * Uncomment for true daemon mode
     * if (fork() != 0) exit(1); // parent exits
     * close(0);
     * close(1);
     * close(2);
     * setsid();
     * open("/dev/null");
     * dup(0);
     * dup(0);
     * chdir("/");
     */
    if (listen(sockfd, 5) < 0)
        error("Error listening to the socket");

    while (1) {
        clilen = sizeof(cli_addr);
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0)
            error("Error accepting socket");
        fprintf(stderr, "connect from %s\n", inet_ntoa(cli_addr.sin_addr));
        if (!fork()) handle_socket(newsockfd); // give child to handle
        close(newsockfd);
    }
}
