#include #include #include #include #include #include #include #include #include #include "stlfile.h" #include "util.h" #define MAXFILESIZE 1000000 struct command { const char *name; void (*func)(const char *); const char *desc; }; int save_submission(struct parseinfo *info, char *data, int len); void cat_cmd(const char *arg); void help_cmd(const char *arg); void exit_cmd(const char *arg); void echo_cmd(const char *arg); void upload_cmd(const char *arg); void search_cmd(const char *arg); void list_cmd(const char *arg); void auth_cmd(const char *arg); void cleanexit(); struct command commands[] = { { "cat", cat_cmd, "Cat cmd go prrrrr." }, { "help", help_cmd, "You already know what this does." }, { "exit", exit_cmd, "Closes the session." }, { "echo", echo_cmd, "Repeat after me!" }, { "upload", upload_cmd, "Upload an STL file to analyze." }, { "search", search_cmd, "Search for an STL file by model name." }, { "list", list_cmd, "List your uploaded files." }, { "auth", auth_cmd, "Login to upload files to a private dir." } }; struct parseinfo cached = { 0 }; char *resultdir; int echo = 0, loggedin = 0; int save_submission(struct parseinfo *info, char *stldata, int stlsize) { char *dirpath = NULL, *infopath = NULL, *modeldir = NULL, *indexpath = NULL, *modelpath = NULL; FILE *f = NULL; int status = OK; modeldir = aprintf("%s%s-%i", loggedin ? "." : "", info->hash, time(NULL)); dirpath = aprintf("%s/%s", resultdir, modeldir); if (mkdir(dirpath, S_IRWXU | S_IRWXG | S_IRWXO)) goto fail; modelpath = aprintf("%s/%s", dirpath, "model"); if (!(f = fopen(modelpath, "w+"))) goto fail; if (fwrite(stldata, 1, stlsize, f) != stlsize) goto fail; FCLOSE(f); infopath = aprintf("%s/%s", dirpath, "info"); if (!(f = fopen(infopath, "w+"))) goto fail; if (save_info(info, f) != OK) goto fail; FCLOSE(f); indexpath = aprintf("%s/.index", resultdir); if (!(f = fopen(indexpath, "a+"))) goto fail; flock(fileno(f), LOCK_EX); fwrite(modeldir, 1, strlen(modeldir), f); fputc('\n', f); flock(fileno(f), LOCK_UN); FCLOSE(f); exit: FCLOSE(f); free(dirpath); free(modelpath); free(infopath); free(indexpath); free(modeldir); return status; fail: if (infopath) remove(infopath); if (modelpath) remove(modelpath); if (dirpath) remove(dirpath); status = FAIL; goto exit; } int access_authorized(const char *file) { return (loggedin && file[0] == '.' && file[1] != '.') || (!loggedin && file[0] != '.'); } int handle_download(const char *scandir) { char *infopath = NULL, *modelpath = NULL; size_t i, size; int status = OK; FILE *f; infopath = aprintf("%s/%s", scandir, "info"); if (!(f = fopen(infopath, "r"))) { ERR("Selected result is missing!\n"); goto fail; } free_info(&cached); if (load_info(&cached, f) != OK) { ERR("Failed to parse info file!\n"); goto fail; } FCLOSE(f); print_info(&cached); if (strchr(ask("> Download model? "), 'y')) { modelpath = aprintf("%s/%s", scandir, "model"); if (!(f = fopen(modelpath, "r"))) { ERR("Failed to access file!\n"); goto fail; } fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); if (size >= MAXFILESIZE) { ERR("File is too large!\n"); goto fail; } printf("Here you go.. (%liB)\n", size); while ((i = getc(f)) != EOF) putc(i, stdout); FCLOSE(f); } exit: if (f) fclose(f); free(infopath); free(modelpath); return status; fail: status = FAIL; goto exit; } void motd() { char linebuf[80]; int msgc, msgi, i; FILE *f; if (!(f = fopen("msgs/motd", "r"))) return; if (!fgets(linebuf, sizeof(linebuf), f)) goto exit; srand(time(NULL)); if ((msgc = atoi(linebuf))) { msgi = rand() % msgc; for (i = 0; i < msgi + 1; i++) if (!fgets(linebuf, sizeof(linebuf), f)) return; printf("%s\n", linebuf); } exit: fclose(f); } void cat_cmd(const char *arg) { if (arg && !strncmp(arg, "flag", 4)) dump("msgs/cat_flag"); else printf("meow\n"); } void help_cmd(const char *arg) { int i; for (i = 0; arg && i < ARRSIZE(commands); i++) { if (!strcmp(commands[i].name, arg)) { printf("%s\n", commands[i].desc); return; } } printf("Available commands:\n"); for (i = 0; i < ARRSIZE(commands); i++) printf("%s%s", i ? " " : "", commands[i].name); printf("\n"); } void exit_cmd(const char *arg) { printf("bye!\n"); exit(0); } void echo_cmd(const char *arg) { echo ^= 1; printf("Echo is %s\n", echo ? "enabled" : "disabled"); } void upload_cmd(const char *arg) { char *end, *contents = NULL, *modelname = NULL; const char *resp; size_t len; modelname = checkp(strdup(ask("> Model name: "))); if (!strlen(modelname)) { ERR("Empty model names are not allowed"); goto exit; } resp = ask("> File size: "); len = strtoul(resp, &end, 10); if (len <= 0 || len >= MAXFILESIZE || *end) { ERR("Invalid file length!\n"); goto exit; } printf("Ok! Im listening..\n"); contents = checkp(malloc(len + 1)); if (fread(contents, 1, len, stdin) != len) { ERR("Not enough data received!\n"); goto exit; } contents[len] = '\0'; if ((cached.valid = parse_file(&cached, contents, len, &modelname))) { if (save_submission(&cached, contents, len) != OK) ERR("Failed to save your submission!\n"); else printf("Your file was saved with ID %s!\n", cached.hash); } exit: free(contents); free(modelname); } void search_cmd(const char *arg) { const char *hash, *resp = NULL; char *indexpath = NULL, *seldir = NULL; FILE *f; int i, c, matchlen, reslen; if (arg && !strcmp(arg, "last")) { if (!cached.valid) { ERR("No cached info report available\n"); return; } hash = cached.hash; } else { hash = mhash(arg ? arg : ask("> Model name: "), -1); } indexpath = aprintf("%s/.index", resultdir); if (!(f = fopen(indexpath, "r"))) { ERR("Sorry, no files currently available\n"); goto exit; } flock(fileno(f), LOCK_SH); reslen = matchlen = 0; while ((c = fgetc(f)) > 0) { if (c == '\n') { matchlen = 0; continue; } else if (matchlen == -1) { continue; } else if (!matchlen && c == '.') { if (!loggedin) matchlen = -1; continue; } else if (c == hash[matchlen]) { matchlen += 1; } else { matchlen = -1; } if (matchlen == strlen(hash)) { fseek(f, -matchlen, SEEK_CUR); putchar(' '); if (loggedin) putchar('.'); while ((c = fgetc(f)) > 0 && c != '\n') putchar(c); putchar('\n'); matchlen = 0; reslen += 1; } } flock(fileno(f), LOCK_UN); fclose(f); if (!reslen) { ERR("Sorry, no files matching that name\n"); goto exit; } while (1) { resp = ask("> Enter %s [q to quit]: ", resp ? "another" : "hash"); if (strchr(resp, 'q')) break; if (checkalph(resp, ".abcdef0123456789-") != OK) { ERR("Invalid model id specified\n"); goto exit; } seldir = aprintf("%s/%s", resultdir, resp); if (handle_download(seldir) != OK) goto exit; FREE(seldir); } exit: free(seldir); free(indexpath); return; } void list_cmd(const char *arg) { struct parseinfo info; char buf[256], *path; FILE *f, *fn; if (!loggedin) { ERR("Not logged in!\n"); return; } path = aprintf("%s/.index", resultdir); if (!(f = fopen(path, "r"))) { ERR("Failed to get files index\n"); free(path); return; } free(path); flock(fileno(f), LOCK_SH); while (fgets(buf, sizeof(buf), f)) { if (*buf && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; printf(">> %s\n", buf); path = aprintf("%s/%s/info", resultdir, buf); if ((fn = fopen(path, "r")) && load_info(&info, fn) == OK) { print_info(&info); free_info(&info); } else { ERR("Failed to read file info!\n"); } if (fn) fclose(f); free(path); } flock(fileno(f), LOCK_UN); fclose(f); } void auth_cmd(const char *arg) { const char *hash; char *ndir, *indexpath; int ret; FILE *f; if (loggedin) { ERR("Already logged in!\n"); return; } hash = mhash(arg ? arg : ask("> Enter a password: "), -1); ndir = aprintf("%s/.%s", resultdir, hash); ret = mkdir(ndir, S_IRWXU | S_IRWXG | S_IRWXO); if (!ret) { printf("Success!\n"); } else if (ret && errno == EEXIST) { printf("Success!\nWelcome back!\n"); } else { ERR("Auth failed!\n"); return; } if (errno != EEXIST) { indexpath = aprintf("%s/.index", resultdir); if (!(f = fopen(indexpath, "a+"))) { free(indexpath); ERR("Auth failed!\n"); return; } flock(fileno(f), LOCK_EX); fputc('.', f); fwrite(hash, 1, strlen(hash), f); fputc('\n', f); flock(fileno(f), LOCK_UN); fclose(f); free(indexpath); } free(resultdir); resultdir = ndir; loggedin = 1; free_info(&cached); } void cleanexit() { free_info(&cached); free(resultdir); } int main() { const char *cmd, *envstr; int exit, i, cmdlen; char *cp, *arg; if (!(envstr = getenv("RESULTDIR"))) die("RESULTDIR not defined\n"); resultdir = checkp(strdup(envstr)); setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); atexit(cleanexit); dump("msgs/banner"); motd(); exit = 0; while (!exit) { errno = 0; cmd = ask("\r$ "); if (!*cmd && errno == EBADMSG) break; if (!*cmd) continue; cp = strchr(cmd, ' '); arg = cp ? cp + 1 : NULL; cmdlen = cp ? cp - cmd : strlen(cmd); for (i = 0; i < ARRSIZE(commands); i++) { if (!strncmp(commands[i].name, cmd, cmdlen) && !commands[i].name[cmdlen]) { commands[i].func(arg); break; } } if (i == ARRSIZE(commands) && strlen(cmd) != 0) ERR("No such command!\n"); } return EXIT_SUCCESS; }