#include #include #include #include #include #include #include #include #include #include #include #include "Server.h" int getMailCounter() { FILE* test = fopen("mailcounter", "r+"); if(test == NULL) { if(creat("mailcounter", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { return 0; } test = fopen("mailcounter", "r+"); if(test == NULL) { return 0; } } int counter; if(fread(&counter, sizeof(int), 1, test) == 0) { counter = -1; } counter++; rewind(test); if(fwrite(&counter, sizeof(int), 1, test) == 0) { return 0; } if(fflush(test) == EOF) { return 0; } if(fclose(test) == EOF) { return 0; } return counter; } int isSpecialFolder(char* folder) { return strcmp(folder, ".") == 0 || strcmp(folder, "..") == 0; } Server server; void interruptHandler(int signal) { serverRemove(&server); exit(EXIT_SUCCESS); } void ensureBufferSize(char** data, int* size, int minSize) { if(minSize >= *size) { int newSize = *size; while(newSize <= minSize) { newSize *= 2; } //printf("Resize from %d to %d\n", *size, newSize); char* newData = malloc(sizeof(char) * newSize); memcpy(newData, *data, *size); *size = newSize; free(*data); *data = newData; } } void packageSendFailAnswer(int clientSocket) { Stream out; streamInit(&out, 16); streamWriteInt(&out, 0); streamWriteChars(&out, "ERR\n"); serverSend(clientSocket, &out); streamRemove(&out); } void packageSendOkAnswer(int clientSocket) { Stream out; streamInit(&out, 16); streamWriteInt(&out, 0); streamWriteChars(&out, "OK\n"); serverSend(clientSocket, &out); streamRemove(&out); } int createDirectory(char* path) { DIR* dir = opendir(path); if(dir == NULL) { if(mkdir(path, S_ISUID | S_ISGID | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { perror("create dir fail"); return -1; } dir = opendir(path); if(dir == NULL) { perror("open dir fail"); return -1; } } if(closedir(dir)) { perror("close dir fail"); return -1; } if(chdir(path) == -1) { perror("change dir fail"); return -1; } return 0; } void storeMail(char* sender, char* receiver, char* subject, char* message) { /*printf("sender: %s\n", sender); printf("receiver: %s\n", receiver); printf("subject: %s\n", subject); printf("message: %s\n", message);*/ if(createDirectory(receiver) == -1) { return; } int id = getMailCounter(); if(createDirectory(sender) == -1) { return; } char buffer[12]; snprintf(buffer, 12, "%d", id); if(createDirectory(buffer) == -1) { return; } if(creat(subject, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { return; } FILE* file = fopen(subject, "w"); if(file == NULL) { perror("cant open file"); return; } if(fputs(message, file) == EOF) { perror("cant write to file"); return; } if(fflush(file) == EOF) { perror("cant flush the file"); return; } if(fclose(file) == EOF) { perror("cant close"); return; } } int packageSend(int client, int clientSocket, Stream* in) { char c; int i; const char* error = "invalid SEND package\n"; // sender i = 0; char sender[9]; while(1) { if(streamGetChar(in, &c) != -1) { if(c == '\n') { sender[i] = '\0'; break; } else { if(i == 8) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } sender[i] = c; i++; } } else { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } } if(strlen(sender) == 0) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } // receiver i = 0; char receiver[9]; while(1) { if(streamGetChar(in, &c) != -1) { if(c == '\n') { receiver[i] = '\0'; break; } else { if(i == 8) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } receiver[i] = c; i++; } } else { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } } if(strlen(receiver) == 0) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } // subject i = 0; char subject[81]; while(1) { if(streamGetChar(in, &c) != -1) { if(c == '\n') { subject[i] = '\0'; break; } else { if(i == 80) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } subject[i] = c; i++; } } else { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } } if(strlen(subject) == 0) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } // message i = 0; int buffer = 16; char* message = malloc(sizeof(char) * buffer); while(1) { if(streamGetChar(in, &c) != -1) { if(c == '\n') { char n1; if(streamGetChar(in, &n1) == -1) { printf("%s", error); packageSendFailAnswer(clientSocket); free(message); return 0; } char n2; if(streamGetChar(in, &n2) == -1) { printf("%s", error); packageSendFailAnswer(clientSocket); free(message); return 0; } if(n1 == '.' && n2 == '\n') { ensureBufferSize(&message, &buffer, i); message[i] = '\0'; break; } else { ensureBufferSize(&message, &buffer, i + 2); message[i] = c; i++; message[i] = n1; i++; message[i] = n2; i++; continue; } } ensureBufferSize(&message, &buffer, i); message[i] = c; i++; } else { printf("%s", error); packageSendFailAnswer(clientSocket); free(message); return 0; } } char workingPath[256]; if(getcwd(workingPath, 256) != NULL) { storeMail(sender, receiver, subject, message); assert(chdir(workingPath) == 0); } free(message); packageSendOkAnswer(clientSocket); return 0; } void sendMailList(char* user, Stream* out) { DIR* dir = opendir(user); if(dir == NULL) { streamWriteInt(out, 0); return; } assert(chdir(user) == 0); int counterPos = streamGetPosition(out); streamWriteInt(out, 0); int counter = 0; struct dirent* pDir = readdir(dir); while(pDir != NULL) { if(strcmp(pDir->d_name, ".") != 0 && strcmp(pDir->d_name, "..") != 0) { DIR* innerdir = opendir(pDir->d_name); if(innerdir != NULL) { assert(chdir(pDir->d_name) == 0); struct dirent* idDir = readdir(innerdir); while(idDir != NULL) { if(strcmp(idDir->d_name, ".") != 0 && strcmp(idDir->d_name, "..") != 0) { counter++; DIR* innerIdDir = opendir(idDir->d_name); if(innerIdDir != NULL) { struct dirent* mails = readdir(innerIdDir); while(mails != NULL) { if(strcmp(mails->d_name, ".") != 0 && strcmp(mails->d_name, "..") != 0) { streamWriteChars(out, idDir->d_name); streamWriteChars(out, " - "); streamWriteChars(out, mails->d_name); streamWriteChar(out, '\n'); } mails = readdir(innerIdDir); } closedir(innerIdDir); } } idDir = readdir(innerdir); } assert(chdir("../") == 0); closedir(innerdir); } } pDir = readdir(dir); } int current = streamGetPosition(out); streamSetPosition(out, counterPos); streamWriteInt(out, counter); streamSetPosition(out, current); closedir(dir); } int packageList(int client, int clientSocket, Stream* in) { char c; int i; const char* error = "invalid LIST package\n"; // user i = 0; char user[9]; while(1) { if(streamGetChar(in, &c) != -1) { if(c == '\n') { user[i] = '\0'; break; } else { if(i == 8) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } user[i] = c; i++; } } else { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } } if(strlen(user) == 0) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } Stream out; streamInit(&out, 16); streamWriteInt(&out, 1); char workingPath[256]; if(getcwd(workingPath, 256) != NULL) { sendMailList(user, &out); assert(chdir(workingPath) == 0); } serverSend(clientSocket, &out); streamRemove(&out); return 0; } void readMail(char* user, int number, Stream* out) { DIR* dir = opendir(user); if(dir == NULL) { streamWriteChars(out, "ERR\n"); return; } assert(chdir(user) == 0); char buffer[12]; snprintf(buffer, 12, "%d", number); struct dirent* senders; senders = readdir(dir); while(senders != NULL) { if(strcmp(senders->d_name, ".") != 0 && strcmp(senders->d_name, "..") != 0) { if(chdir(senders->d_name) == 0) { DIR* innerDir = opendir(buffer); if(innerDir != NULL) { struct dirent* mail; mail = readdir(innerDir); while(mail != NULL && (strcmp(mail->d_name, ".") == 0 || strcmp(mail->d_name, "..") == 0)) { mail = readdir(innerDir); } if(mail != NULL) { assert(chdir(buffer) == 0); FILE* file = fopen(mail->d_name, "r"); if(file != NULL) { struct stat stats; if(stat(mail->d_name, &stats) == 0) { char* filebuffer = malloc(sizeof(char) * (stats.st_size + 1)); if(fgets(filebuffer, stats.st_size + 1, file) != NULL) { streamWriteChars(out, "OK\n"); streamWriteChars(out, filebuffer); streamWriteChar(out, '\n'); } else { streamWriteChars(out, "ERR\n"); } } else { streamWriteChars(out, "ERR\n"); } if(fclose(file) == EOF) { perror("cannot close file"); } } else { streamWriteChars(out, "ERR\n"); } } else { streamWriteChars(out, "ERR\n"); } if(closedir(innerDir) == -1) { perror("cannot close innerDir"); } if(closedir(dir) == -1) { perror("cannot close dir"); } return; } assert(chdir("../") == 0); } } senders = readdir(dir); } if(closedir(dir) == -1) { perror("cannot close dir"); } streamWriteChars(out, "ERR\n"); } int packageRead(int client, int clientSocket, Stream* in) { char c; int i; const char* error = "invalid READ package\n"; // user i = 0; char user[9]; while(1) { if(streamGetChar(in, &c) != -1) { if(c == '\n') { user[i] = '\0'; break; } else { if(i == 8) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } user[i] = c; i++; } } else { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } } if(strlen(user) == 0) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } int number; if(streamGetInt(in, &number) == -1) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } if(streamGetChar(in, &c) == -1) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } else if(c != '\n') { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } Stream out; streamInit(&out, 16); streamWriteInt(&out, 2); char workingPath[256]; if(getcwd(workingPath, 256) != NULL) { readMail(user, number, &out); assert(chdir(workingPath) == 0); } else { streamWriteChars(&out, "ERR\n"); } serverSend(clientSocket, &out); streamRemove(&out); return 0; } int deleteMail(char* user, int number) { DIR* dir = opendir(user); if(dir == NULL) { return 0; } assert(chdir(user) == 0); char buffer[12]; snprintf(buffer, 12, "%d", number); int rValue = 0; struct dirent* senders; senders = readdir(dir); while(senders != NULL) { if(strcmp(senders->d_name, ".") != 0 && strcmp(senders->d_name, "..") != 0) { if(chdir(senders->d_name) == 0) { DIR* innerDir = opendir(buffer); if(innerDir != NULL) { if(chdir(buffer) == -1) { perror("cannot change dir"); if(closedir(innerDir) == -1) { perror("cannot close innerDir"); } break; } rValue = 1; struct dirent* mail; mail = readdir(innerDir); while(mail != NULL) { if(!isSpecialFolder(mail->d_name) && remove(mail->d_name) == -1) { perror("cannot delete file"); rValue = 0; } mail = readdir(innerDir); } if(closedir(innerDir) == -1) { perror("cannot close innerDir"); rValue = 0; } if(chdir("../") == 0) { if(rmdir(buffer) == -1) { perror("cannot remove dir"); rValue = 0; } } else { perror("cannot change dir"); rValue = 0; } break; } if(chdir("../") == -1) { perror("cannot change dir"); break; } } } senders = readdir(dir); } if(closedir(dir) == -1) { perror("cannot close dir"); } return rValue; } int packageDelete(int client, int clientSocket, Stream* in) { char c; int i; const char* error = "invalid DELETE package\n"; // user i = 0; char user[9]; while(1) { if(streamGetChar(in, &c) != -1) { if(c == '\n') { user[i] = '\0'; break; } else { if(i == 8) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } user[i] = c; i++; } } else { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } } if(strlen(user) == 0) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } int number; if(streamGetInt(in, &number) == -1) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } if(streamGetChar(in, &c) == -1) { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } else if(c != '\n') { printf("%s", error); packageSendFailAnswer(clientSocket); return 0; } Stream out; streamInit(&out, 16); streamWriteInt(&out, 2); char workingPath[256]; if(getcwd(workingPath, 256) != NULL) { if(deleteMail(user, number)) { streamWriteChars(&out, "OK\n"); } else { streamWriteChars(&out, "ERR\n"); } assert(chdir(workingPath) == 0); } else { streamWriteChars(&out, "ERR\n"); } serverSend(clientSocket, &out); streamRemove(&out); return 0; } int packageQuit(int client, int clientSocket, Stream* in) { printf("%d wants to disconnect ...\n", client); return 1; } int main(int argc, char** argv) { if(argc < 2) { printf("Usage: %s directory\n", argv[0]); return EXIT_FAILURE; } serverInitDefaults(&server); signal(SIGINT, interruptHandler); signal(SIGKILL, interruptHandler); if(serverInit(&server, 3, 6543, argv[1]) == -1) { return EXIT_FAILURE; } serverRegisterHandler(&server, packageSend); serverRegisterHandler(&server, packageList); serverRegisterHandler(&server, packageRead); serverRegisterHandler(&server, packageDelete); serverRegisterHandler(&server, packageQuit); serverWaitForConnection(&server); serverRemove(&server); return EXIT_SUCCESS; }