/* * Plists.c */ #include <stdlib.h> #include <ctype.h> #include <time.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <memory.h> #include <signal.h> #include <setjmp.h> #include "fix.h" #include "config.h" #include "player.h" /* externs */ extern int restore_player_title(player *, char *, char *); extern void decompress_list(saved_player *); extern char *end_string(), *retrieve_room_data(), *retrieve_list_data(), *retrieve_mail_data(), *retrieve_alias_data(), *retrieve_item_data(); extern void construct_room_save(), construct_list_save(), construct_mail_save(), construct_alias_save(), construct_item_save(); extern void decompress_room(room *); extern void decompress_alias(saved_player *); extern void decompress_item(saved_player *); extern void log(char *, char *); extern void handle_error(char *); extern void free_room_data(saved_player *); extern void players_update_function(player *p); extern void initialise_data(player *p); extern char *get_int(int *dest, char *source); extern char *get_string(char *dest, char *source); extern char *store_string(char *dest, char *source); extern char *store_int(char *dest, int source); extern void extra_save_data(player *p); extern void extra_load_data(player *p, char *r); /* interns */ void error_on_load(); int bad_player_load = 0; char player_loading[MAX_NAME + 2]; jmp_buf jmp_env; saved_player **saved_hash[26]; int update[26]; void save_player(); int restore_player(); void do_update() { player *p; saved_player *scan, **hash; int i, j, fd; fd = open("/dev/null", O_WRONLY); p = (player *) MALLOC(sizeof(player)); for (j = 0; j < 26; j++) { hash = saved_hash[j]; for (i = 0; i < HASH_SIZE; i++, hash++) { for (scan = *hash; scan; scan = scan->next) { if (scan->residency != STANDARD_ROOMS && scan->residency != SYSTEM_ROOM) /* &&(scan->residency != BANISHED) && (scan->residency != BANISHD))*/ { memset((char *) p, 0, sizeof(player)); p->fd = fd; p->script = 0; p->location = (room *) - 1; restore_player(p, scan->lower_name); save_player(p); } } } } close(fd); } /* saved player stuff */ /* see if a saved player exists (given lower case name) */ saved_player *find_saved_player(char *name) { saved_player **hash, *list; int sum = 0,h; char *c; if (!isalpha(*name)) return 0; hash = saved_hash[((int) (tolower(*name)) - (int) 'a')]; for (c = name; *c; c++) { if (isalpha(*c)) sum += (int) (tolower(*c)) - 'a'; else return 0; } list = *(hash + (sum % HASH_SIZE)); for (; list; list = list->next) if (!strcmp(name, list->lower_name)) return list; return 0; } /* hard load and save stuff (ie to disk and back) */ int load_player(player * p) { saved_player *sp; char *r; lower_case(p->lower_name); sp = find_saved_player(p->lower_name); p->saved = sp; if (!sp) return 0; p->residency = sp->residency; p->saved_residency = p->residency; p->system_flags = sp->system_flags; p->tag_flags = sp->tag_flags; p->custom_flags = sp->custom_flags; p->misc_flags = sp->misc_flags; p->pennies = sp->pennies; if (sp->residency == BANISHED || sp->residency == STANDARD_ROOMS || sp->residency == SYSTEM_ROOM || sp->residency == BANISHD) return 1; r = sp->data.where; r = get_string(p->name, r); r = get_string(p->prompt, r); r = get_string(p->converse_prompt, r); r = get_string(p->email, r); r = get_string(p->password, r); r = get_string(p->title, r); r = get_string(p->plan, r); r = get_string(p->description, r); r = get_string(p->enter_msg, r); r = get_string(p->pretitle, r); r = get_string(p->ignore_msg, r); r = get_string(p->room_connect, r); r = get_int(&p->term_width, r); r = get_int(&p->word_wrap, r); r = get_int(&p->max_rooms, r); r = get_int(&p->max_exits, r); r = get_int(&p->max_autos, r); r = get_int(&p->max_list, r); r = get_int(&p->max_mail, r); r = get_int(&p->gender, r); r = get_int(&p->no_shout, r); r = get_int(&p->total_login, r); r = get_int(&p->term, r); r = get_int(&p->birthday, r); r = get_int(&p->age, r); r = get_int(&p->jetlag, r); r = get_int(&p->sneezed, r); r = get_string(p->logonmsg, r); r = get_string(p->logoffmsg, r); r = get_string(p->blockmsg, r); r = get_string(p->exitmsg, r); r = get_int(&p->time_in_main, r); r = get_int(&p->no_sing, r); r = get_string(p->married_to, r); r = get_string(p->irl_name, r); r = get_string(p->alt_email, r); r = get_string(p->hometown, r); r = get_string(p->spod_class, r); r = get_string(p->favorite1, r); r = get_string(p->favorite2, r); r = get_string(p->favorite3, r); r = get_int(&p->total_idle_time, r); r = get_int(&p->max_alias, r); r = get_string(p->colorset, r); r = get_string(p->ressied_by, r); r = get_string(p->git_string, r); r = get_string(p->git_by, r); r = get_int(&p->warn_count, r); r = get_int(&p->eject_count, r); r = get_int(&p->idled_out_count, r); r = get_int(&p->booted_count, r); r = get_int(&p->num_ressied, r); r = get_int(&p->num_warned, r); r = get_int(&p->num_ejected, r); r = get_int(&p->num_rmd, r); r = get_int(&p->num_booted, r); r = get_int(&p->first_login_date, r); r = get_int(&p->max_items, r); r = get_int(&p->prs_record, r); r = get_string(p->ingredients, r); extra_load_data(p, r); decompress_list(sp); decompress_alias(sp); decompress_item(sp); p->system_flags = sp->system_flags; p->tag_flags = sp->tag_flags; p->custom_flags = sp->custom_flags; p->misc_flags = sp->misc_flags; p->pennies = sp->pennies; return 1; } file construct_save_data(player * p) { file d; d.where = stack; /* Initialise any new variables */ initialise_data(p); players_update_function(p); stack = store_string(stack, p->name); stack = store_string(stack, p->prompt); stack = store_string(stack, p->converse_prompt); stack = store_string(stack, p->email); if (p->password[0] == -1) p->password[0] = 0; stack = store_string(stack, p->password); stack = store_string(stack, p->title); stack = store_string(stack, p->plan); stack = store_string(stack, p->description); stack = store_string(stack, p->enter_msg); stack = store_string(stack, p->pretitle); stack = store_string(stack, p->ignore_msg); stack = store_string(stack, p->room_connect); stack = store_int(stack, p->term_width); stack = store_int(stack, p->word_wrap); stack = store_int(stack, p->max_rooms); stack = store_int(stack, p->max_exits); stack = store_int(stack, p->max_autos); stack = store_int(stack, p->max_list); stack = store_int(stack, p->max_mail); stack = store_int(stack, p->gender); stack = store_int(stack, p->no_shout); stack = store_int(stack, p->total_login); stack = store_int(stack, p->term); stack = store_int(stack, p->birthday); stack = store_int(stack, p->age); stack = store_int(stack, p->jetlag); stack = store_int(stack, p->sneezed); stack = store_string(stack, p->logonmsg); stack = store_string(stack, p->logoffmsg); stack = store_string(stack, p->blockmsg); stack = store_string(stack, p->exitmsg); stack = store_int(stack, p->time_in_main); stack = store_int(stack, p->no_sing); stack = store_string(stack, p->married_to); stack = store_string(stack, p->irl_name); stack = store_string(stack, p->alt_email); stack = store_string(stack, p->hometown); stack = store_string(stack, p->spod_class); stack = store_string(stack, p->favorite1); stack = store_string(stack, p->favorite2); stack = store_string(stack, p->favorite3); stack = store_int(stack, p->total_idle_time); stack = store_int(stack, p->max_alias); stack = store_string(stack, p->colorset); stack = store_string(stack, p->ressied_by); stack = store_string(stack, p->git_string); stack = store_string(stack, p->git_by); stack = store_int(stack, p->warn_count); stack = store_int(stack, p->eject_count); stack = store_int(stack, p->idled_out_count); stack = store_int(stack, p->booted_count); stack = store_int(stack, p->num_ressied); stack = store_int(stack, p->num_warned); stack = store_int(stack, p->num_ejected); stack = store_int(stack, p->num_rmd); stack = store_int(stack, p->num_booted); stack = store_int(stack, p->first_login_date); stack = store_int(stack, p->max_items); stack = store_int(stack, p->prs_record); stack = store_string(stack, p->ingredients); extra_save_data(p); d.length = (int) stack - (int) d.where; stack = d.where; return d; } /* extract one player */ void extract_player(char *where, int length) { int len, sum; char *oldstack, *c; saved_player *old, *sp, **hash; oldstack = stack; where = get_int(&len, where); where = get_string(oldstack, where); stack = end_string(oldstack); old = find_saved_player(oldstack); sp = old; if (!old) { sp = (saved_player *) MALLOC(sizeof(saved_player)); memset((char *) sp, 0, sizeof(saved_player)); strncpy(sp->lower_name, oldstack, MAX_NAME); strncpy(player_loading, sp->lower_name, MAX_NAME); sp->rooms = 0; sp->mail_sent = 0; sp->mail_received = 0; sp->list_top = 0; hash = saved_hash[((int) sp->lower_name[0] - (int) 'a')]; for (sum = 0, c = sp->lower_name; *c; c++) sum += (int) (*c) - 'a'; hash = (hash + (sum % HASH_SIZE)); sp->next = *hash; *hash = sp; } where = get_int(&sp->last_on, where); where = get_int(&sp->system_flags, where); where = get_int(&sp->tag_flags, where); where = get_int(&sp->custom_flags, where); where = get_int(&sp->misc_flags, where); where = get_int(&sp->pennies, where); where = get_int(&sp->residency, where); if (sp->residency == BANISHED) sp->residency = BANISHD; if (sp->residency == BANISHD) { sp->last_host[0] = 0; sp->data.where = 0; sp->data.length = 0; stack = oldstack; return; } /* PUT ANYTHING TO CHANGE RESIDENCY OR OTHER FLAGS HERE */ where = get_string(sp->last_host, where); where = get_string(sp->email, where); where = get_int(&sp->data.length, where); sp->data.where = (char *) MALLOC(sp->data.length); memcpy(sp->data.where, where, sp->data.length); where += sp->data.length; where = retrieve_room_data(sp, where); where = retrieve_list_data(sp, where); where = retrieve_alias_data(sp, where); where = retrieve_item_data(sp, where); where = retrieve_mail_data(sp, where); stack = oldstack; } /* hard load in on player file */ void hard_load_one_file(char c) { char *oldstack, *where, *scan; int fd, length, len2, i, fromjmp; oldstack = stack; if (sys_flags & VERBOSE) { sprintf(oldstack, "Loading player file '%c'.", c); stack = end_string(oldstack); log("boot", oldstack); stack = oldstack; } #ifdef PC sprintf(oldstack, "files\\players\\%c", c); fd = open(oldstack, O_RDONLY | O_BINARY); #else sprintf(oldstack, "%s%c", rc_options->pfile_path,c); fd = open(oldstack, O_RDONLY | O_NDELAY); #endif if (fd < 0) { sprintf(oldstack, "Failed to load player file '%c'", c); stack = end_string(oldstack); log("error", oldstack); } else { length = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); if (length) { where = (char *) MALLOC(length); if (read(fd, where, length) < 0) handle_error("Can't read player file."); for (i = 0, scan = where; i < length;) { get_int(&len2, scan); fromjmp = setjmp(jmp_env); if (!fromjmp && !bad_player_load) { extract_player(scan, len2); } else { sprintf(oldstack, "Bad Player \'%s\' deleted on load.", player_loading); stack = end_string(oldstack); log("boot", oldstack); stack = oldstack; remove_player_file(player_loading); bad_player_load = 0; } i += len2; scan += len2; } FREE(where); } close(fd); } stack = oldstack; } /* load in all the player files */ void hard_load_files() { char c; int i, hash_length; char *oldstack; oldstack = stack; hash_length = HASH_SIZE * sizeof(saved_player *); for (i = 0; i < 26; i++) { saved_hash[i] = (saved_player **) MALLOC(hash_length); memset((void *) saved_hash[i], 0, hash_length); } for (c = 'a'; c <= 'z'; c++) hard_load_one_file(c); } /* write one player file out */ void write_to_file(saved_player * sp) { char *oldstack; int length; #ifdef PLIST_TRACK printf("write_to_file:%s\n", sp->lower_name); #endif oldstack = stack; if (sys_flags & VERBOSE && sys_flags & PANIC) { sprintf(oldstack, "Attempting to write player '%s'.", sp->lower_name); stack = end_string(oldstack); log("sync", oldstack); stack = oldstack; } stack += 4; stack = store_string(stack, sp->lower_name); stack = store_int(stack, sp->last_on); stack = store_int(stack, sp->system_flags); stack = store_int(stack, sp->tag_flags); stack = store_int(stack, sp->custom_flags); stack = store_int(stack, sp->misc_flags); stack = store_int(stack, sp->pennies); stack = store_int(stack, sp->residency); if ((sp->residency != BANISHED) ) { stack = store_string(stack, sp->last_host); stack = store_string(stack, sp->email); stack = store_int(stack, sp->data.length); memcpy(stack, sp->data.where, sp->data.length); stack += sp->data.length; construct_room_save(sp); construct_list_save(sp); construct_alias_save(sp); construct_item_save(sp); construct_mail_save(sp); } length = (int) stack - (int) oldstack; (void) store_int(oldstack, length); } /* sync player files corresponding to one letter */ void sync_to_file(char c, int background) { saved_player *scan, **hash; char *oldstack; int fd, i, length; #ifdef PLIST_TRACK_TEST printf("sync_to_file(%c)\n", c); #endif if (background && fork()) return; oldstack = stack; if (sys_flags & VERBOSE) { sprintf(oldstack, "Syncing File '%c'.", c); stack = end_string(oldstack); log("sync", oldstack); stack = oldstack; } hash = saved_hash[((int) c - (int) 'a')]; for (i = 0; i < HASH_SIZE; i++, hash++) for (scan = *hash; scan; scan = scan->next) if (scan->residency != STANDARD_ROOMS && scan->residency != SYSTEM_ROOM) write_to_file(scan); length = (int) stack - (int) oldstack; /* test that you can write out a file ok */ sprintf(stack, "%sbackup_write", rc_options->new_pfile_path); fd = open(stack, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) handle_error("Primary open failed (player back)"); if (write(fd, oldstack, length) < 0) handle_error("Primary write failed " "(playerback)"); close(fd); sprintf(stack, "%s%c", rc_options->new_pfile_path, c); fd = open(stack, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) handle_error("Failed to open player file."); if (write(fd, oldstack, length) < 0) handle_error("Failed to write player file."); close(fd); update[(int) c - (int) 'a'] = 0; stack = oldstack; if (background) exit(0); } /* sync everything to disk */ void sync_all() { char c, *oldstack; oldstack = stack; for (c = 'a'; c <= 'z'; c++) sync_to_file(c, 0); } /* flicks on the update flag for a particular player hash */ void set_update(char c) { update[(int) c - (int) 'a'] = 1; } /* removes an entry from the saved player lists */ int remove_player_file(char *name) { saved_player *previous = 0, **hash, *list; char *c; int sum = 0; if (!isalpha(*name)) { log("error", "Tried to remove non-player from save files."); return 0; } strcpy(stack, name); lower_case(stack); hash = saved_hash[((int) (*stack) - (int) 'a')]; for (c = stack; *c; c++) { if (isalpha(*c)) sum += (int) (*c) - 'a'; else { log("error", "Remove bad name from save files"); return 0; } } hash += (sum % HASH_SIZE); list = *hash; for (; list; previous = list, list = list->next) { if (!strcmp(stack, list->lower_name)) { if (previous) previous->next = list->next; else *hash = list->next; if (list->data.where) FREE(list->data.where); if (list->mail_received) FREE(list->mail_received); free_room_data(list); FREE((void *) list); set_update(*stack); return 1; } } return 0; } /* the routine that sets everything up for the save */ void save_player(player * p) { saved_player *old, **hash, *sp; int sum; file data; char *c, *oldstack; int verb = 1; oldstack = stack; if (!(p->location) || !(p->name[0]) || p->residency == NON_RESIDENT) return; if (sys_flags & PANIC) { c = stack; sprintf(c, "Attempting to save player %s.", p->name); stack = end_string(c); log("boot", c); stack = c; } if (!(isalpha(p->lower_name[0]))) { log("error", "Tried to save non-player."); return; } if (p->residency & SYSTEM_ROOM) verb = 0; if (verb) { if (!(p->password[0] && p->password[0] != -1)) { p->residency |= NO_SYNC; stack = oldstack; return; } if (p->email[0] == 2) { p->residency |= NO_SYNC; stack = oldstack; return; } } p->residency &= ~NO_SYNC; p->saved_residency = p->residency; old = p->saved; sp = old; if (!old) { sp = (saved_player *) MALLOC(sizeof(saved_player)); memset((char *) sp, 0, sizeof(saved_player)); strncpy(sp->lower_name, p->lower_name, MAX_NAME); sp->rooms = 0; sp->mail_sent = 0; sp->mail_received = 0; sp->list_top = 0; hash = saved_hash[((int) p->lower_name[0] - (int) 'a')]; for (sum = 0, c = p->lower_name; *c; c++) { if (isalpha(*c)) sum += (int) (*c) - 'a'; else { FREE(sp); return; } } hash = (hash + (sum % HASH_SIZE)); sp->next = *hash; *hash = sp; p->saved = sp; sp->system_flags = p->system_flags; sp->tag_flags = p->tag_flags; sp->custom_flags = p->custom_flags; sp->misc_flags = p->misc_flags; sp->pennies = p->pennies; create_room(p); } data = construct_save_data(p); if (!data.length) { log("error", "Bad construct save."); return; } if (old && sp->data.where) FREE((void *) sp->data.where); sp->data.where = (char *) MALLOC(data.length); sp->data.length = data.length; memcpy(sp->data.where, data.where, data.length); sp->residency = p->saved_residency; sp->system_flags = p->system_flags; sp->tag_flags = p->tag_flags; sp->custom_flags = p->custom_flags; sp->misc_flags = p->misc_flags; sp->pennies = p->pennies; set_update(*(sp->lower_name)); p->saved = sp; } /* load from a saved player into a current player */ /* load and do linking */ int restore_player(player * p, char *name) { return restore_player_title(p, name, 0); } int restore_player_title(player * p, char *name, char *title) { int did_load; int found_lower; char *n; strncpy(p->name, name, MAX_NAME - 2); strncpy(p->lower_name, name, MAX_NAME - 2); lower_case(p->lower_name); if (!strcmp(p->name, p->lower_name)) p->name[0] = toupper(p->name[0]); found_lower = 0; n = p->name; while (*n) { if (*n >= 'a' && *n <= 'z') { found_lower = 1; } *n++; } if (!found_lower) { n = p->name; *n++; while (*n) { *n = *n - ('A' - 'a'); *n++; } } did_load = load_player(p); strcpy(p->assisted_by, ""); if (title && *title) { strncpy(p->title, title, MAX_TITLE); p->title[MAX_TITLE] = 0; } if ((p->system_flags & IAC_GA_ON) && (!(p->flags & EOR_ON))) p->flags |= IAC_GA_DO; else p->flags &= ~IAC_GA_DO; if (p->residency == 0 && did_load == 1) p->residency = SYSTEM_ROOM; if (p->system_flags & SAVEDFROGGED) p->flags |= FROGGED; if (p->residency & PSU) p->no_shout = 0; p->saved_residency = p->residency; if ((p->word_wrap) > ((p->term_width) >> 1) || p->word_wrap < 0) p->word_wrap = (p->term_width) >> 1; if (p->term > 9) p->term = 0; return did_load; } /* init everything needed for the plist file */ void init_plist() { char *oldstack; int i; oldstack = stack; hard_load_files(); for (i = 0; i < 26; i++) update[i] = 1; stack = oldstack; } /* Catch SEGV's and BUS's on load of players, hopefully... */ void error_on_load() { bad_player_load = 1; longjmp(jmp_env, 0); longjmp(jmp_env, 0); }