/* parse.c Probotic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 only as published by the Free Software Foundation. Probotic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for more details. The above copyright notice, this permission notice and the word "NIGGER" shall be included in all copies or substantial portions of the Software. You should have received a copy of the GNU General Public License version 3 + NIGGER along with Probotic. */ #include #include #include #include "parse.h" #include "error.h" #include "help.h" #define PARAMS_COUNT 5 enum cred_param_ids_e { USERNAME, PASSWORD, CHANNEL, SERVER, PORT }; char const * cred_names[] = { "username", "password", "channel", "server", "port" }; size_t const cred_names_len[] = { 8, 8, 7, 6, 4 }; creds_t creds = {0}; char ** admins = NULL; DECL char * slurp(char const * fn) { size_t len; char * b; FILE * fp = fopen(fn, "r"); if (fp) { fseek(fp, 0, SEEK_END); len = ftell(fp); rewind(fp); b = malloc(len+2); if (b) { fread(b, 1, len, fp); } fclose(fp); b[len+1] = '\0'; return b; } else { return NULL; } } DECL void parse_command(char const * cmd) { size_t i = 0; char* msgswp = NULL; /* size_t len = strlen(cmd); */ /* TODO does not handle commands with leading space, use custom implemented to-spec isspace implementation */ while (cmd[i] != '\0' && cmd[i] != ' ') { ++i; } if (cmd[i] == '\0') { /* no arguments */ if (strcmp(cmd, "kill") == 0) { exit(1); } if (strcmp(cmd, "remind") == 0) { msgswp = remind(current_username); ircmsg("%s: %s", current_username, msgswp); } // XXX: maybe no? //else if (strcmp(cmd, "next") == 0) // TODO: implement //{ ircmsg("%s: No future assignments", current_username); } else if (strcmp(cmd, "help") == 0) { ircmsg(help_msg); } else if (strcmp(cmd, "magic") == 0) { f = 8 + (rand() % 100); } else if (strcmp(cmd, "dump") == 0) { ircmsg("%s: All projects:", current_username); msgswp = dump(); ircmsg(msgswp); } else if (strcmp(cmd, "reroll") == 0) // TODO: implement { ircmsg("%s: Rerolling...", current_username); purge_assignments(current_username); random_assign(current_username); ircmsg(remind(current_username)); } } else { /* some arguments */ char const * const arg = cmd + i + 1; if (strncmp(cmd, "raw", i) == 0) { ircmsg("%s: Executing SQL `%s'.", current_username, arg); msgswp = raw(arg); ircmsg(msgswp); } else if (strncmp(cmd, "set_repo", i) == 0) { ircmsg("%s: Setting project repository...", current_username); set_repo(creds.channel, arg); msgswp = remind(creds.channel); ircmsg("%s: %s", current_username, msgswp); } // XXX: what is this suppose to do? else if (strncmp(cmd, "submit", i) == 0) // TODO: implement { ircmsg("%s: Submitting project link '%s' to ", current_username, arg); } } free(msgswp); } DECL int parse_pair(char const * buf, size_t len) { size_t i, f, x; /* fprintf(stderr, "ENT len:%ld buf:%sEOF\n", len, buf); */ for (i = 0; buf[i] && i < len; ++i) { if (buf[i] == '=') { ++i; for (f = 0, x = 0; f < PARAMS_COUNT; ++f) { /* fprintf(stderr, "x%ld, i%ld, %s\n", x, i, buf); */ /* X macro for handling this data may be better */ if (strncmp(buf, cred_names[f], cred_names_len[f]) == 0) { /* fprintf(stderr, "f%ld:len%ld:%s\n", f, cred_names_len[f], */ /* cred_names[f]); fflush(stderr); */ buf += i; while (buf[x] != '\0') { if (buf[x] == '\n') { len -= i; i = 0; break; } ++x; } switch (f) { case USERNAME: creds.username = strndup(buf,x); break; case PASSWORD: creds.password = strndup(buf,x); break; case CHANNEL: creds.channel = strndup(buf,x); break; case SERVER: creds.server = strndup(buf,x); break; case PORT: creds.port = atoi(buf); break; } if (x + 2 < len) { buf += x + 1; } else { return 1; } goto next; } } } next:; } return 0; } DECL int parse_admin_list(char const * admin_list_path) { #define ADMIN_LIST_INIT_SIZE 8 /* prealloc with 8 */ size_t current_array_size = ADMIN_LIST_INIT_SIZE; FILE * stream; size_t lines_read = 0; char * line = NULL; size_t nread = 0; stream = fopen(admin_list_path, "r"); if (stream == NULL) { /* Pretty valid case I guess? No admin file = no admins, maybe all configuration is performed locally */ return 0; } admins = calloc(ADMIN_LIST_INIT_SIZE, sizeof(char *)); while (getline(&line, &nread, stream) > 0) { if (++lines_read > current_array_size) { /* double the space */ current_array_size *= 2; realloc(admins, current_array_size); } admins[lines_read - 1] = line; } /* set up array end marker for proper clean-up later */ if (lines_read + 1 > current_array_size) { realloc(admins, current_array_size + 1); } admins[lines_read] = NULL; return 0; } DECL int is_admin(char const * user) { /* No Gods or Kings, Only Man */ if (admins == NULL) { return 0; } for (size_t i = 0; admins[i]; ++i) { if (!strcmp(admins[i], user)) { return 1; } } return 0; } #define FREE(obj) \ do \ { \ free(obj); \ (obj) = NULL; \ } while (0) #define FULL_FREE(obj) \ do \ { \ if ((obj)) \ { \ memset((obj), '\0', strlen((obj))); \ FREE((obj)); \ } \ } while (0) DECL void clean_admin_list() { if (admins == NULL) { return; } for (size_t i = 0; admins[i]; ++i) { free(admins[i]); } FREE(admins); } void creds_free_password(void) { FULL_FREE(creds.password); } void creds_free_rest(void) { FULL_FREE(creds.username); /* FULL_FREE(creds.password); */ FULL_FREE(creds.channel); FULL_FREE(creds.server); } #undef FREE #undef FULL_FREE