#include #include #include #include #include #include #include #include "util.hpp" #define VALID_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" enum Command parse_command(char* line){ /* Find a valid command in the first word of the line (case sensitive) args: line (char*): string of characters from the input file returns: (command): Returns the found command. Returns else if first word is invalid. */ if (line == NULL){ return INVALID; } char* rest; char* tok = strtok_r(line, " ", &rest); if (tok == NULL){ return INVALID; } // REGISTER [username] [password] if (strcmp(tok, "REGISTER") == 0){ char* username = strtok_r(rest, " ", &rest); if(!isValidUsername(username)) return INVALID; char* password = strtok_r(rest, " ", &rest); if(password == NULL) return INVALID; if(!isValidPassword(password)) return INVALID; char* misc = strtok_r(rest, " ", &rest); if(misc != NULL) return INVALID; return REGISTER; } // LOGIN [username] [password] if (strcmp(tok, "LOGIN") == 0){ char* username = strtok_r(rest, " ", &rest); if(!isValidUsername(username)) return INVALID; char* password = strtok_r(rest, " ", &rest); if(password == NULL) return INVALID; if(!isValidPassword(password)) return INVALID; char* misc = strtok_r(rest, " ", &rest); if(misc != NULL) return INVALID; return LOGIN; } // LOGOUT if (strcmp(tok, "LOGOUT") == 0){ char* misc = strtok_r(rest, " ", &rest); if(misc != NULL) return INVALID; return LOGOUT; } // SEND [msg] if (strcmp(tok, "SEND") == 0){ if (int(strlen(rest) == 0)) return INVALID; return SEND; } // SEND2 [username] [msg] if (strcmp(tok, "SEND2") == 0){ char* username = strtok_r(rest, " ", &rest); if(!isValidUsername(username)) return INVALID; if (int(strlen(rest) == 0)) return INVALID; return SEND2; } // SENDA [msg] if (strcmp(tok, "SENDA") == 0){ if (int(strlen(rest) == 0)) return INVALID; return SENDA; } // SENDA2 [username] [msg] if (strcmp(tok, "SENDA2") == 0){ char* username = strtok_r(rest, " ", &rest); if(!isValidUsername(username)) return INVALID; if (int(strlen(rest) == 0)) return INVALID; return SENDA2; } // SENDF [local file] if (strcmp(tok, "SENDF") == 0){ char* file_name = strtok_r(rest, " ", &rest); if(file_name == NULL) return INVALID; if (int(strlen(rest) != 0)) return INVALID; return SENDF; } // SENDF2 [username] [local file] if (strcmp(tok, "SENDF2") == 0){ char* username = strtok_r(rest, " ", &rest); if(!isValidUsername(username)) return INVALID; char* file_name = strtok_r(rest, " ", &rest); if(file_name == NULL) return INVALID; if (int(strlen(rest) != 0)) return INVALID; return SENDF2; } // LIST if (strcmp(tok, "LIST") == 0){ char* misc = strtok_r(rest, " ", &rest); if(misc != NULL) return INVALID; return LIST; } // DELAY if (strcmp(tok, "DELAY") == 0){ char* delay_time = strtok_r(rest, " ", &rest); if(delay_time == NULL) return INVALID; std::string str(delay_time); std::size_t found = str.find_first_not_of("0123456789"); if(found != std::string::npos) return INVALID; if (int(strlen(rest) != 0)) return INVALID; return DELAY; } // default return INVALID; } bool isValidUsername(char* username){ /* Helper function to check if a username string is valid args: username (char*): Username to be tested. returns: bool: Username is valid ? true, false */ if(username == NULL) return false; else if ((strlen(username) > MAX_USERNAME_LEN)||(strlen(username) < MIN_USERNAME_LEN)) return false; else{ std::string str(username); std::size_t found = str.find_first_not_of(VALID_CHARACTERS); if(found != std::string::npos) return false; } return true; } bool isValidPassword(char* password){ if(password == NULL) return false; else if ((strlen(password) > MAX_PASSWORD_LEN)||(strlen(password) < MIN_PASSWORD_LEN)) return false; else{ std::string str(password); std::size_t found = str.find_first_not_of(VALID_CHARACTERS); if(found != std::string::npos) return false; } return true; } void Error(const char * format, ...) { char msg[4096]; va_list argptr; va_start(argptr, format); vsprintf(msg, format, argptr); va_end(argptr); fprintf(stderr, "Error: %s\n", msg); exit(-1); } void Log(const char * format, ...) { char msg[2048]; va_list argptr; va_start(argptr, format); vsprintf(msg, format, argptr); va_end(argptr); fprintf(stderr, "%s\n", msg); } // convert buf[0:3] to int void buf2i(BYTE * buf, int &i){ // No way to avoid Segmentation fault. Some bytes may be 0 i = 0; i += buf[3]; i += ((int)(buf[2])) << 8; i += ((int)(buf[1])) << 16; i += ((int)(buf[0])) << 24; } // convert int to buf[4] where buf[0] contains MSB's and buf[3] contains LSB's void i2buf(int &i, BYTE * buf){ // No way to avoid Segmentation fault. Some bytes may be 0 buf[0] = (BYTE)((i & 0xFF000000) >> 24); buf[1] = (BYTE)((i & 0x00FF0000) >> 16); buf[2] = (BYTE)((i & 0x0000FF00) >> 8); buf[3] = (BYTE)(i & 0x000000FF); } const char * com2str(enum Command command){ const char * com2str[] = {"REGISTER", "LOGIN", "LOGOUT", "SEND", "SEND2", "SENDA", "SENDA2", "SENDF", "SENDF2", "LIST", "DELAY", "GETF", "PING", "CONNECT", "", "INVALID" }; return com2str[command]; } // Computes the difference between times a and b in seconds // a - b = result double timeDifference(struct timeb a, struct timeb b){ return (a.time + a.millitm / (double) 1000.0f) - (b.time + b.millitm / (double) 1000.0f); } int getNumEntries(const char* database){ FILE* fp = fopen(database, "r"); if (!fp){ Log("Username check failed to open the file: %s", database); return -1; } int numEntries = 0; char line[LINE_SIZE] = {0}; while(fgets(line, LINE_SIZE, fp) != NULL){ char* new_line_pos = strchr(line, '\n'); if(new_line_pos != NULL) *new_line_pos = 0; // Including blank lines as entries. Don't use any blank lines. numEntries++; memset(line, 0, LINE_SIZE); } fclose(fp); return numEntries; } // User/password is in registry: true // User/password is not in registry: false bool loginQuery(const char * database, char* username, char* password){ FILE* fp = fopen(database, "r"); if (!fp){ Log("Registry check failed to open the file: %s", database); return false; } char line[LINE_SIZE] = {0}; while(fgets(line, LINE_SIZE, fp) != NULL){ char* new_line_pos = strchr(line, '\n'); if(new_line_pos != NULL) *new_line_pos = 0; char* rest; char* usr = strtok_r(line, " ", &rest); char* pswd = strtok_r(rest, " ", &rest); //Log("username: |%s| Password: |%s|", usr, pswd); if((strcmp(username, usr) == 0) && (strcmp(password, pswd) == 0)){ fclose(fp); return true; } memset(line, 0, LINE_SIZE); } fclose(fp); return false; } // User is in registry: true // User is not in registry: false bool usernameQuery(const char * database, char* username){ FILE* fp = fopen(database, "r"); if (!fp){ Log("Username check failed to open the file: %s", database); return false; } char line[LINE_SIZE] = {0}; while(fgets(line, LINE_SIZE, fp) != NULL){ char* new_line_pos = strchr(line, '\n'); if(new_line_pos != NULL) *new_line_pos = 0; char* rest; char* usr = strtok_r(line, " ", &rest); //Log("username: |%s|", usr); if(strcmp(username, usr) == 0){ fclose(fp); return true; } memset(line, 0, LINE_SIZE); } fclose(fp); return false; } void recordEntry(const char * database, char* key, char* value){ FILE* fp = fopen(database, "a"); if (!fp){ Log("Registry append failed to open the file: %s", database); return; } char line[LINE_SIZE] = {0}; strcat(line, key); strcat(line, " "); strcat(line, value); strcat(line, "\n"); fputs(line, fp); fclose(fp); } void clearDatabase(const char * database){ FILE* fp = fopen(database, "w"); fclose(fp); } int buf2file(BYTE* buf, int nbytes, char* filename){ FILE* f = fopen(filename, "w"); if(!f) return -1; fwrite(buf, 1, nbytes, f); fclose(f); return 0; } int file2buf(char* filename, BYTE* buf){ FILE* f = fopen(filename, "r"); if(!f){ Log("Error: Cannot open %s", filename); return -1; } fseek(f, 0, SEEK_END); // jump to end of file long nbytes = ftell(f); // find current offset on file f fseek(f, 0, SEEK_SET); // jump to beginning of file if(nbytes > MAX_REQUEST_SIZE){ Log("Error: File %s is too big: %d", filename, nbytes); return -1; } int nread = fread(buf, 1, nbytes, f); if(nread != nbytes){ Log("Error: Byte count mismatch with fread: %d, %d", nbytes, nread); return -1; } fclose(f); return nbytes; }