#define _POSIX_C_SOURCE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include "Server.h" int getMailCounter() { FILE* test = fopen("mailcounter", "r+"); flock(fileno(test), LOCK_EX); 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; } flock(fileno(test), LOCK_UN); 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(creat(buffer, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { return; } FILE* file = fopen(buffer, "w"); if(file == NULL) { perror("cant open file"); return; } if(fputs(subject, file) == EOF) { perror("cant write to file"); return; } if(fputc('\n', file) == EOF) { perror("cant write to 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* user = serverGetUser(&server, client); if(user == NULL) { packageSendFailAnswer(clientSocket); return 0; } char c; int i; const char* error = "invalid SEND package\n"; // 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 || isSpecialFolder(receiver)) { 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(user, receiver, subject, message); assert(chdir(workingPath) == 0); } free(message); packageSendOkAnswer(clientSocket); return 0; } void sendMailList(char* user, Stream* out) { DIR* receiverDir = opendir(user); if(receiverDir == NULL) { streamWriteInt(out, 0); return; } assert(chdir(user) == 0); int counterPos = streamGetPosition(out); streamWriteInt(out, 0); int counter = 0; struct dirent* receiverIterator = readdir(receiverDir); while(receiverIterator != NULL) { if(!isSpecialFolder(receiverIterator->d_name)) { DIR* senderDir = opendir(receiverIterator->d_name); if(senderDir != NULL) { assert(chdir(receiverIterator->d_name) == 0); struct dirent* senderIterator = readdir(senderDir); while(senderIterator != NULL) { if(!isSpecialFolder(senderIterator->d_name)) { // mails found counter++; // reading subject from first line FILE* file = fopen(senderIterator->d_name, "r"); if(file != NULL) { int size = 16; int pos = 0; char* buffer = malloc(sizeof(char) * size); int data; while(1) { data = fgetc(file); if(data == '\n' || data == EOF) { ensureBufferSize(&buffer, &size, pos); buffer[pos] = '\0'; break; } ensureBufferSize(&buffer, &size, pos); buffer[pos] = data; pos++; } streamWriteChars(out, senderIterator->d_name); streamWriteChars(out, " - "); streamWriteChars(out, buffer); free(buffer); streamWriteChar(out, '\n'); if(fclose(file) == EOF) { perror("cannot close file"); } } else { streamWriteChars(out, "ERR\n"); } } senderIterator = readdir(senderDir); } assert(chdir("../") == 0); closedir(senderDir); } } receiverIterator = readdir(receiverDir); } int current = streamGetPosition(out); streamSetPosition(out, counterPos); streamWriteInt(out, counter); streamSetPosition(out, current); closedir(receiverDir); } int packageList(int client, int clientSocket, Stream* in) { char* user = serverGetUser(&server, client); if(user == NULL) { 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* receiverDir = opendir(user); if(receiverDir == NULL) { streamWriteChars(out, "ERR\n"); return; } assert(chdir(user) == 0); char buffer[12]; snprintf(buffer, 12, "%d", number); struct dirent* receiverIterator; receiverIterator = readdir(receiverDir); while(receiverIterator != NULL) { if(!isSpecialFolder(receiverIterator->d_name)) { if(chdir(receiverIterator->d_name) == 0) { FILE* file = fopen(buffer, "r"); if(file != NULL) { // skip subject heading int data; while(1) { data = fgetc(file); if(data == '\n' || data == EOF) { break; } } // write data to stream while(1) { data = fgetc(file); if(data == EOF) { break; } streamWriteChar(out, data); } if(fclose(file) == EOF) { perror("cannot close file"); } if(closedir(receiverDir) == -1) { perror("cannot close receiver dir"); } return; } assert(chdir("../") == 0); } } receiverIterator = readdir(receiverDir); } if(closedir(receiverDir) == -1) { perror("cannot close dir"); } streamWriteChars(out, "ERR\n"); } int packageRead(int client, int clientSocket, Stream* in) { char* user = serverGetUser(&server, client); if(user == NULL) { packageSendFailAnswer(clientSocket); return 0; } char c; const char* error = "invalid READ package\n"; 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* receiverDir = opendir(user); if(receiverDir == NULL) { return 0; } assert(chdir(user) == 0); char buffer[12]; snprintf(buffer, 12, "%d", number); int rValue = 0; struct dirent* receiverIterator; receiverIterator = readdir(receiverDir); while(receiverIterator != NULL) { if(!isSpecialFolder(receiverIterator->d_name)) { if(chdir(receiverIterator->d_name) == 0) { if(remove(buffer) == 0) { rValue = 1; break; } assert(chdir("../") == 0); } } receiverIterator = readdir(receiverDir); } if(closedir(receiverDir) == -1) { perror("cannot close dir"); } return rValue; } int packageDelete(int client, int clientSocket, Stream* in) { char* user = serverGetUser(&server, client); if(user == NULL) { packageSendFailAnswer(clientSocket); return 0; } char c; const char* error = "invalid DELETE package\n"; 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 packageLogin(int client, int clientSocket, Stream* in) { printf("%d wants to login ...\n", client); 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; } // password i = 0; int buffer = 16; char* password = malloc(sizeof(char) * buffer); while(1) { if(streamGetChar(in, &c) != -1) { if(c == '\n') { ensureBufferSize(&password, &buffer, i); password[i] = '\0'; break; } ensureBufferSize(&password, &buffer, i); password[i] = c; i++; } else { printf("%s", error); packageSendFailAnswer(clientSocket); free(password); return 0; } } printf("%s %s\n", user, password); // insert LDAP check here if(serverSetUser(&server, client, user)) { packageSendFailAnswer(clientSocket); free(password); return 0; } free(password); packageSendOkAnswer(clientSocket); return 0; } int main(int argc, char** argv) { if(argc < 3) { printf("Usage: %s directory port\n", argv[0]); return EXIT_FAILURE; } int port = atoi(argv[2]); if(port <= 0 || port >= 65536) { printf("invalid port"); return EXIT_FAILURE; } serverInitDefaults(&server); signal(SIGINT, interruptHandler); signal(SIGKILL, interruptHandler); if(serverInit(&server, 3, port, argv[1]) == -1) { return EXIT_FAILURE; } serverRegisterHandler(&server, packageSend); serverRegisterHandler(&server, packageList); serverRegisterHandler(&server, packageRead); serverRegisterHandler(&server, packageDelete); serverRegisterHandler(&server, packageQuit); serverRegisterHandler(&server, packageLogin); serverWaitForConnection(&server); serverRemove(&server); return EXIT_SUCCESS; }