int main (int argc, char **argv) { uint32_t c; char *config_file; bool custom_config; char *tmpdir; struct sigaction sigact; set_quoting_style(NULL, escape_quoting_style); if (setlocale(LC_ALL, "") == NULL) warn(_("%s: Cannot set locale: %s\n"), argv[0], errstr); #ifdef ENABLE_NLS if (bindtextdomain(PACKAGE, LOCALEDIR) == NULL) warn(_("%s: Cannot bind message domain: %s\n"), argv[0], errstr); if (textdomain(PACKAGE) == NULL) warn(_("%s: Cannot set message domain: %s\n"), argv[0], errstr); #endif custom_config = false; get_package_file("config", &config_file); while (true) { c = getopt_long(argc, argv, short_opts, long_opts, NULL); if (c == -1) break; switch (c) { case 'c': /* --config */ custom_config = true; free(config_file); config_file = xstrdup(optarg); break; case 'n': /* --no-config */ free(config_file); config_file = NULL; break; case HELP_OPT: /* --help */ printf(_("Usage: %s [OPTION]...\n"), quotearg(argv[0])); puts(_("Start microdc, a command-line based Direct Connect client.\n")); printf(_(" -n, --no-config do not read config file on startup\n")); printf(_(" --help display this help and exit\n")); printf(_(" --version output version information and exit\n")); printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); exit(EXIT_SUCCESS); case VERSION_OPT: /* --version */ version_etc(stdout, NULL, PACKAGE, VERSION, /*"Oskar Liljeblad",*/ "Vladimir Chugunov", NULL); exit(EXIT_SUCCESS); default: exit(EXIT_FAILURE); } } if (pipe(signal_pipe) < 0) { warn(_("Cannot create pipe pair - %s\n"), errstr); goto cleanup; } main_process_id = getpid(); sigact.sa_handler = signal_received; if (sigemptyset(&sigact.sa_mask) < 0) { warn(_("Cannot empty signal set - %s\n"), errstr); goto cleanup; } sigact.sa_flags = SA_RESTART; #ifdef HAVE_STRUCT_SIGACTION_SA_RESTORER sigact.sa_restorer = NULL; #endif /* Note: every signal registered with a non-ignore action here must * also be registered in user.c, either with an action or as ignored. */ if (sigaction(SIGINT, &sigact, NULL) < 0 || sigaction(SIGTERM, &sigact, NULL) < 0 || sigaction(SIGUSR1, &sigact, NULL) < 0 || sigaction(SIGCHLD, &sigact, NULL) < 0) { warn(_("Cannot register signal handler - %s\n"), errstr); goto cleanup; } sigact.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sigact, NULL) < 0) { warn(_("Cannot register signal handler - %s\n"), errstr); goto cleanup; } FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_SET(signal_pipe[0], &read_fds); /*FD_SET(STDIN_FILENO, &read_fds);*/ hub_recvq = byteq_new(128); hub_sendq = byteq_new(128); user_conns = hmap_new(); hub_users = hmap_new(); pending_userinfo = hmap_new(); set_main_charset(""); set_hub_charset(""); set_fs_charset(""); user_conn_unknown_free = ptrv_new(); delete_files = ptrv_new(); delete_dirs = ptrv_new(); search_udpmsg_out = ptrv_new(); our_searches = ptrv_new(); search_recvq = byteq_new(8192); // same size as DC++ my_nick = xstrdup(PACKAGE); my_description = xstrdup(""); my_email = xstrdup(""); my_speed = xstrdup("56Kbps"); my_tag = xasprintf("%s V:%s", PACKAGE, VERSION); download_dir = xstrdup("."); tmpdir = tempdir(); if (tmpdir == NULL) { warn(_("Cannot find directory for temporary files - %s\n"), errstr); goto cleanup; } { char *filename = xasprintf("%s.%d", PACKAGE, getpid()); listing_dir = catfiles(tmpdir, filename); free(filename); } ptrv_append(delete_dirs, xstrdup(listing_dir)); is_active = false; listen_port = 0; if (!local_file_list_update_init()) goto cleanup; if (!set_active(false, listen_port)) goto cleanup; if (!enable_search()) goto cleanup; my_ul_slots = 3; if (!lookup_init()) goto cleanup; if (!file_list_parse_init()) goto cleanup; command_init(); if (!local_file_list_init()) { goto cleanup; } if (config_file != NULL) { run_script(config_file, !custom_config); free(config_file); config_file = NULL; } screen_prepare(); while (running) { fd_set res_read_fds; fd_set res_write_fds; int res; struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; screen_redisplay_prompt(); res_read_fds = read_fds; res_write_fds = write_fds; res = TEMP_FAILURE_RETRY(select(FD_SETSIZE, &res_read_fds, &res_write_fds, NULL, &tv)); if (res < 0) { warn(_("Cannot select - %s\n"), errstr); break; } if (running && FD_ISSET(signal_pipe[0], &res_read_fds)) read_signal_input(); if (running && FD_ISSET(STDIN_FILENO, &res_read_fds)) screen_read_input(); if (running && listen_socket >= 0 && FD_ISSET(listen_socket, &res_read_fds)) handle_listen_connection(); if (running && hub_socket >= 0 && FD_ISSET(hub_socket, &res_read_fds)) hub_input_available(); if (running && hub_socket >= 0 && FD_ISSET(hub_socket, &res_write_fds)) hub_now_writable(); if (running) check_hub_activity(); if (running && search_socket >= 0 && FD_ISSET(search_socket, &res_read_fds)) search_input_available(); if (running && search_socket >= 0 && FD_ISSET(search_socket, &res_write_fds)) search_now_writable(); if (running && FD_ISSET(lookup_request_mq->fd, &res_write_fds)) lookup_request_fd_writable(); if (running && FD_ISSET(lookup_result_mq->fd, &res_read_fds)) lookup_result_fd_readable(); if (running && FD_ISSET(parse_request_mq->fd, &res_write_fds)) parse_request_fd_writable(); if (running && FD_ISSET(parse_result_mq->fd, &res_read_fds)) parse_result_fd_readable(); if (running && FD_ISSET(update_request_mq->fd, &res_write_fds)) update_request_fd_writable(); if (running && FD_ISSET(update_result_mq->fd, &res_read_fds)) update_result_fd_readable(); if (running) { HMapIterator it; hmap_iterator(user_conns, &it); while (running && it.has_next(&it)) { DCUserConn *uc = (DCUserConn*) it.next(&it); if (uc->put_mq != NULL && FD_ISSET(uc->put_mq->fd, &res_write_fds)) user_request_fd_writable(uc); if (uc->get_mq != NULL && FD_ISSET(uc->get_mq->fd, &res_read_fds)) user_result_fd_readable(uc); } } } cleanup: hub_disconnect(); screen_finish(); command_finish(); local_file_list_update_finish(); file_list_parse_finish(); lookup_finish(); byteq_free(hub_recvq); byteq_free(hub_sendq); hmap_free(hub_users); /* Emptied by hub_disconnect */ hmap_free(pending_userinfo); /* Emptied by hub_disconnect */ byteq_free(search_recvq); ptrv_foreach(user_conn_unknown_free, free); ptrv_free(user_conn_unknown_free); ptrv_foreach(search_udpmsg_out, free); ptrv_free(search_udpmsg_out); ptrv_foreach(our_searches, (PtrVForeachCallback) free_search_request); ptrv_free(our_searches); hmap_foreach_value(user_conns, (void (*) (void*)) user_conn_cancel); /* XXX: follow up and wait for user connections to die? */ hmap_free(user_conns); if (our_filelist != NULL) filelist_free(our_filelist); set_main_charset(NULL); set_hub_charset(NULL); set_fs_charset(NULL); free(hub_name); free(my_nick); free(my_description); free(my_email); free(my_speed); free(my_tag); free(download_dir); free(listing_dir); if (delete_files != NULL) { for (c = 0; c < delete_files->cur; c++) { char *filename = (char*) delete_files->buf[c]; struct stat st; if (stat(filename, &st) < 0) { if (errno != ENOENT) warn(_("%s: Cannot get file status - %s\n"), quotearg(filename), errstr); free(filename); continue; } if (unlink(filename) < 0) warn(_("%s: Cannot remove file - %s\n"), quotearg(filename), errstr); free(filename); } ptrv_free(delete_files); } if (delete_dirs != NULL) { for (c = 0; c < delete_dirs->cur; c++) { char *filename = (char*) delete_dirs->buf[c]; struct stat st; if (stat(filename, &st) < 0) { if (errno != ENOENT) warn(_("%s: Cannot get file status - %s\n"), quotearg(filename), errstr); free(filename); continue; } if (rmdir(filename) < 0) warn(_("%s: Cannot remove file - %s\n"), quotearg(filename), errstr); free(filename); } ptrv_free(delete_dirs); } if (search_socket >= 0 && close(search_socket) < 0) warn(_("Cannot close search results socket - %s\n"), errstr); if (listen_socket >= 0 && close(listen_socket) < 0) warn(_("Cannot close user connections socket - %s\n"), errstr); if (signal_pipe[0] >= 0 && close(signal_pipe[0]) < 0) warn(_("Cannot close signal pipe - %s\n"), errstr); if (signal_pipe[1] >= 0 && close(signal_pipe[1]) < 0) warn(_("Cannot close signal pipe - %s\n"), errstr); free(config_file); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { char user[64]; screen_init(); if (setjmp(fatal_error_jmp_buf) == 0) { char *setname = DEFAULTSET; levelset *set; level *l; gamestate *gs; progress p; int i, action, n, saveslot = 0; gamestate *saves[10]; get_user(user, sizeof(user)); /* * Pick up argv[1] in case it describes an alternate level * set. */ if (argc > 1) setname = argv[1]; set = levelset_load(setname); p = progress_load(set, user); for (i = 0; i < 10; i++) saves[i] = savepos_load(set, user, i); while (1) { action = screen_main_menu(set, saves, p.levnum+1, p.levnum); if (action > 0) { l = set->levels[action-1]; gs = init_game(l); gs->levnum = action; saveslot = 0; } else if (action == -100) { break; /* direct quit from main menu */ } else if (action <= -10) { /* delete a saved position */ n = -action-10; if (saves[n]) gamestate_free(saves[n]); saves[n] = NULL; savepos_del(set, user, n); gs = NULL; } else { /* load a saved position */ n = -action; if (!saves[n]) /* don't segfault */ continue; gs = gamestate_copy(saves[n]); l = set->levels[gs->levnum-1]; saveslot = n; } if (gs) { screen_level_init(); while (gs->status == PLAYING) { gamestate *newgs; int k; screen_level_display(gs, NULL); k = screen_level_getmove(); if (k == 'h' || k == 'j' || k == 'l' || k == 'k') { newgs = make_move(gs, k); gamestate_free(gs); gs = newgs; } else if (k == 's') { n = screen_saveslot_ask('s', saves, saveslot); if (n >= 0) { saveslot = n; saves[saveslot] = gamestate_copy(gs); savepos_save(set, user, saveslot, gs); } } else if (k == 'r') { n = screen_saveslot_ask('r', saves, saveslot); if (n >= 0 && saves[n]) { saveslot = n; gamestate_free(gs); gs = gamestate_copy(saves[saveslot]); l = set->levels[gs->levnum-1]; } } else if (k == 'q') { break; } } if (gs->status != PLAYING) { int increased_level = FALSE; char *msg; if (gs->status == DIED) { msg = "GAME OVER"; } else if (gs->status == COMPLETED) { msg = "LEVEL COMPLETE"; if (p.levnum < gs->levnum) { p.levnum = gs->levnum; p.date = time(NULL); progress_save(set, user, p); increased_level = TRUE; } } else { msg = "!INTERNAL ERROR!"; } screen_level_display(gs, msg); screen_level_finish(); if (increased_level && p.levnum == set->nlevels) { screen_completed_game(); } } } } } else { screen_finish(); fprintf(stderr, "Fatal error: %s\n", fatal_error_string); exit(2); } screen_finish(); return 0; }