Exemple #1
0
int main(int argc, char *argv[])
{
	std::string config_path, cmdln_font;
	bool launch_game = false;

	process_args( argc, argv, config_path, cmdln_font );

	//
	// Run the front-end
	//
	std::cout << "Starting " << FE_NAME << " " << FE_VERSION
			<< " (" << get_OS_string() << ")" << std::endl;

	FeSettings feSettings( config_path, cmdln_font );
	feSettings.load();

	if ( feSettings.get_info_bool( FeSettings::AutoLaunchLastGame ) )
	{
		feSettings.select_last_launch();
		launch_game=true;
	}

	std::string defaultFontFile;
	if ( feSettings.get_font_file( defaultFontFile ) == false )
	{
		std::cerr << "Error, could not find default font."  << std::endl;
		return 1;
	}

	FeFontContainer defaultFont;
	defaultFont.set_font( defaultFontFile );

	//
	// Set up music/sound playing objects
	//
#ifndef NO_MOVIE
	sf::AudioDevice audio_device;
#endif
	FeSoundSystem soundsys( &feSettings );

	soundsys.update_volumes();
	soundsys.play_ambient();

	FeWindow window( feSettings );
	window.initial_create();

	FeVM feVM( feSettings, defaultFont, window, soundsys.get_ambient_sound() );
	FeOverlay feOverlay( window, feSettings, feVM );
	feVM.set_overlay( &feOverlay );

	bool exit_selected=false;

	if ( feSettings.get_language().empty() )
	{
		// If our language isn't set at this point, we want to prompt the user for the language
		// they wish to use
		//

		// TODO: FIXME: languages_dialog segfaults unless there is a layout loaded first
		feVM.load_layout( true );

		if ( feOverlay.languages_dialog() < 0 )
			exit_selected = true;
	}

	soundsys.sound_event( FeInputMap::EventStartup );

	bool redraw=true;
	int guard_joyid=-1, guard_axis=-1;

	// variables used to track movement when a key is held down
	FeInputMap::Command move_state( FeInputMap::LAST_COMMAND );
	sf::Clock move_timer;
	sf::Event move_event;
	int move_last_triggered( 0 );

	// go straight into config mode if there are no lists configured for
	// display
	//
	bool config_mode = ( feSettings.displays_count() < 1 );

	if ( !config_mode )
	{
		// start the intro now
		if ( !feVM.load_intro() )
			feVM.load_layout( true );
	}

	while (window.isOpen() && (!exit_selected))
	{
		if ( config_mode )
		{
			//
			// Enter config mode
			//
			int old_mode = feSettings.get_window_mode();
			if ( feOverlay.config_dialog() )
			{
				// Settings changed, reload
				//
				if ( feSettings.get_font_file( defaultFontFile ) )
					defaultFont.set_font( defaultFontFile );

				feSettings.set_display(
					feSettings.get_current_display_index() );

				feVM.load_layout();

				soundsys.stop();
				soundsys.update_volumes();
				soundsys.play_ambient();

				// Recreate window if the window mode changed
				if ( feSettings.get_window_mode() != old_mode )
				{
					window.on_exit();
					window.initial_create();
				}
			}
			feVM.reset_screen_saver();
			config_mode=false;
			redraw=true;
		}
		else if ( launch_game )
		{
			if ( feSettings.get_rom_info( 0, 0, FeRomInfo::Emulator ).compare( "@" ) == 0 )
			{
				// If the rom_info's emulator is set to "@" then this is a shortcut to another
				// display, so instead of running a game we switch to the display specified in the
				// rom_info's Romname field
				//
				std::string name = feSettings.get_rom_info( 0, 0, FeRomInfo::Romname );
				int index = feSettings.get_display_index_from_name( name );

				// if index not found or if we are already in the specified display, then
				// jump to the altromname display instead
				//
				if (( index < 0 ) || ( index == feSettings.get_current_display_index() ))
				{
					name = feSettings.get_rom_info( 0, 0, FeRomInfo::AltRomname );
					if ( !name.empty() )
						index =  feSettings.get_display_index_from_name( name );
				}

				if ( index < 0 )
				{
					std::cerr << "Error resolving shortcut, Display `" << name << "' not found.";
				}
				else
				{
					if ( feSettings.set_display( index ) )
						feVM.load_layout();
					else
						feVM.update_to_new_list( 0, true );
				}
			}
			else
			{
				soundsys.stop();

				feVM.pre_run();

				// window.run() returns true if our window has been closed while the other program was running
				if ( !window.run() )
					exit_selected = true;

				feVM.post_run();

				soundsys.sound_event( FeInputMap::EventGameReturn );
				soundsys.play_ambient();
			}

			launch_game=false;
			redraw=true;
		}

		FeInputMap::Command c;
		sf::Event ev;
		while ( feVM.poll_command( c, ev ) )
		{
			//
			// Special case handling based on event type
			//
			switch ( ev.type )
			{
				case sf::Event::Closed:
					exit_selected = true;
					break;

				case sf::Event::MouseMoved:
					if ( feSettings.test_mouse_reset( ev.mouseMove.x, ev.mouseMove.y ))
					{
						// We reset the mouse if we are capturing it and it has moved
						// outside of its bounding box
						//
						sf::Vector2u s = window.getSize();
						sf::Mouse::setPosition( sf::Vector2i( s.x / 2, s.y / 2 ), window );
					}
					break;

				case sf::Event::KeyPressed:
				case sf::Event::MouseButtonPressed:
				case sf::Event::JoystickButtonPressed:
					//
					// We always want to reset the screen saver on these events,
					// even if they aren't mapped otherwise (mapped events cause
					// a reset too)
					//
					if (( c == FeInputMap::LAST_COMMAND )
							&& ( feVM.reset_screen_saver() ))
						redraw = true;
					break;

				case sf::Event::GainedFocus:
				case sf::Event::Resized:
					redraw = true;
					break;


				case sf::Event::JoystickMoved:
					if ( c == FeInputMap::LAST_COMMAND )
					{
						if (( (int)ev.joystickMove.joystickId == guard_joyid )
							&& ( ev.joystickMove.axis == guard_axis ))
						{
							// Reset the joystick guard because the axis we are guarding has moved
							// below the joystick threshold
							guard_joyid = -1;
							guard_axis = -1;
						}
					}
					else
					{
						// Only allow one mapped "Joystick Moved" input through at a time
						//
						if ( guard_joyid != -1 )
							continue;

						guard_joyid = ev.joystickMove.joystickId;
						guard_axis = ev.joystickMove.axis;
					}
					break;

				case sf::Event::Count:
				default:
					break;
			}

			if (( c == FeInputMap::LAST_COMMAND )
					|| ( move_state != FeInputMap::LAST_COMMAND ))
				continue;

			move_state=FeInputMap::LAST_COMMAND;

			if (( c == FeInputMap::Down )
				|| ( c == FeInputMap::Up )
				|| ( c == FeInputMap::PageDown )
				|| ( c == FeInputMap::PageUp )
				|| ( c == FeInputMap::NextLetter )
				|| ( c == FeInputMap::PrevLetter )
				|| ( c == FeInputMap::NextFavourite )
				|| ( c == FeInputMap::PrevFavourite ))
			{
				// setup variables to test for when the navigation keys are held down
				move_state = c;
				move_timer.restart();
				move_event = ev;
			}

			//
			// Special case: handle the reload signal now
			//
			if ( c == FeInputMap::Reload )
			{
				feVM.load_layout();
				continue;
			}

			//
			// Give the script the option to handle the command.
			//
			if ( feVM.script_handle_event( c, redraw ) )
				continue;

			//
			// Check if we need to get out of intro mode
			//
			if ( feSettings.get_present_state() == FeSettings::Intro_Showing )
			{
				feVM.load_layout( true );
				redraw=true;
				continue;
			}

			//
			// Default command handling
			//
			soundsys.sound_event( c );
			if ( feVM.handle_event( c ) )
				redraw = true;
			else
			{
				// handle the things that fePresent doesn't do
				switch ( c )
				{
				case FeInputMap::ExitMenu:
					{
						int retval = feOverlay.confirm_dialog( "Exit Attract-Mode?" );
						//
						// retval is 0 if the user confirmed exit.
						// it is <0 if we are being forced to close
						//
						if ( retval < 1 )
						{
							exit_selected = true;
							if ( retval == 0 )
								feSettings.exit_command();
						}
						else
							redraw=true;
					}
					break;

				case FeInputMap::ExitNoMenu:
					exit_selected = true;
					break;

				case FeInputMap::ReplayLastGame:
					if ( feSettings.select_last_launch() )
						feVM.load_layout();
					else
						feVM.update_to_new_list();

					launch_game=true;
					redraw=true;
					break;

				case FeInputMap::Select:
					launch_game=true;
					break;

				case FeInputMap::ToggleMute:
					feSettings.set_mute( !feSettings.get_mute() );
					soundsys.update_volumes();
					feVM.toggle_mute();
					break;

				case FeInputMap::ScreenShot:
					{
						std::string filename;
						get_available_filename( feSettings.get_config_dir(),
										"screen", ".png", filename );

						sf::Image sshot_img = window.capture();
						sshot_img.saveToFile( filename );
					}
					break;

				case FeInputMap::Configure:
					config_mode = true;
					break;

				case FeInputMap::DisplaysMenu:
					{
						std::vector<std::string> names_list;
						feSettings.get_display_names( names_list );

						std::string title;
						feSettings.get_resource( "Lists", title );

						int exit_opt=-999;
						if ( feSettings.get_info_bool( FeSettings::DisplaysMenuExit ) )
						{
							//
							// Add an exit option at the end of the lists menu
							//
							std::string exit_str;
							feSettings.get_resource( "Exit Attract-Mode", exit_str );
							names_list.push_back( exit_str );
							exit_opt = names_list.size() - 1;
						}

						int display_index = feOverlay.common_list_dialog(
										title,
										names_list,
										feSettings.get_current_display_index(),
										-1 );

						if ( display_index == exit_opt )
						{
							exit_selected = true;
							feSettings.exit_command();
						}
						else if ( display_index >= 0 )
						{
							if ( feSettings.set_display( display_index ) )
								feVM.load_layout();
							else
								feVM.update_to_new_list( 0, true );
						}
						redraw=true;
					}
					break;

				case FeInputMap::FiltersMenu:
					{
						std::vector<std::string> names_list;
						feSettings.get_current_display_filter_names( names_list );

						std::string title;
						feSettings.get_resource( "Filters", title );

						int filter_index = feOverlay.common_list_dialog(
										title,
										names_list,
										feSettings.get_current_filter_index(),
										-1 );

						if ( filter_index >= 0 )
						{
							feSettings.set_current_selection( filter_index, -1 );
							feVM.update_to_new_list();
						}

						redraw=true;
					}
					break;

				case FeInputMap::ToggleFavourite:
					{
						bool new_state = !feSettings.get_current_fav();

						if ( feSettings.get_info_bool( FeSettings::ConfirmFavourites ) )
						{
							std::string msg = ( new_state )
								? "Add '$1' to Favourites?"
								: "Remove '$1' from Favourites?";

							// returns 0 if user confirmed toggle
							if ( feOverlay.confirm_dialog(
									msg,
									feSettings.get_rom_info( 0, 0, FeRomInfo::Title ) ) == 0 )
							{
								if ( feSettings.set_current_fav( new_state ) )
									feVM.update_to_new_list(); // our current display might have changed, so update
							}
						}
						else
						{
							if ( feSettings.set_current_fav( new_state ) )
								feVM.update_to_new_list(); // our current display might have changed, so update
						}
						redraw = true;
					}
					break;

				case FeInputMap::ToggleTags:
					if ( feOverlay.tags_dialog() < 0 )
						exit_selected = true;

					redraw = true;
					break;

				default:
					break;
				}
			}
		}

		//
		// Determine if we have to do anything because a key is being held down
		//
		if ( move_state != FeInputMap::LAST_COMMAND )
		{
			bool cont=false;

			switch ( move_event.type )
			{
			case sf::Event::KeyPressed:
				if ( sf::Keyboard::isKeyPressed( move_event.key.code ) )
					cont=true;
				break;

			case sf::Event::MouseButtonPressed:
				if ( sf::Mouse::isButtonPressed( move_event.mouseButton.button ) )
					cont=true;
				break;

			case sf::Event::JoystickButtonPressed:
				if ( sf::Joystick::isButtonPressed(
						move_event.joystickButton.joystickId,
						move_event.joystickButton.button ) )
					cont=true;
				break;

			case sf::Event::JoystickMoved:
				{
					sf::Joystick::update();

					float pos = sf::Joystick::getAxisPosition(
							move_event.joystickMove.joystickId,
							move_event.joystickMove.axis );
					if ( abs( pos ) > feSettings.get_joy_thresh() )
						cont=true;
				}
				break;

			default:
				break;
			}

			if ( cont )
			{
				const int TRIG_CHANGE_MS = 400;

				int t = move_timer.getElapsedTime().asMilliseconds();
				if (( t > TRIG_CHANGE_MS ) && ( t - move_last_triggered > feSettings.selection_speed() ))
				{
					move_last_triggered = t;
					int step = 1;

					if ( feSettings.get_info_bool( FeSettings::AccelerateSelection ) )
					{
						// As the button is held down, the advancement accelerates
						int shift = ( t / TRIG_CHANGE_MS ) - 3;
						if ( shift < 0 )
							shift = 0;
						else if ( shift > 7 ) // don't go above a maximum advance of 2^7 (128)
							shift = 7;

						step = 1 << ( shift );
					}

					switch ( move_state )
					{
						case FeInputMap::Up: step = -step; break;
						case FeInputMap::Down: break; // do nothing
						case FeInputMap::PageUp: step *= -feVM.get_page_size(); break;
						case FeInputMap::PageDown: step *= feVM.get_page_size(); break;
						case FeInputMap::PrevFavourite:
							{
								int temp = feSettings.get_prev_fav_offset();
								step = ( temp < 0 ) ? temp : 0;
							}
							break;
						case FeInputMap::NextFavourite:
							{
								int temp = feSettings.get_next_fav_offset();
								step = ( temp > 0 ) ? temp : 0;
							}
							break;
						case FeInputMap::PrevLetter:
							{
								int temp = feSettings.get_next_letter_offset( -1 );
								step = ( temp < 0 ) ? temp : 0;
							}
							break;
						case FeInputMap::NextLetter:
							{
								int temp = feSettings.get_next_letter_offset( 1 );
								step = ( temp > 0 ) ? temp : 0;
							}
							break;
						default: break;
					}

					//
					// Limit the size of our step so that there is no wrapping around at the end of the list
					//
					int curr_sel = feSettings.get_rom_index( feSettings.get_current_filter_index(), 0 );
					if ( ( curr_sel + step ) < 0 )
						step = -curr_sel;
					else
					{
						int list_size = feSettings.get_filter_size( feSettings.get_current_filter_index() );
						if ( ( curr_sel + step ) >= list_size )
							step = list_size - curr_sel - 1;
					}

					if (( step != 0 ) && ( feVM.script_handle_event( move_state, redraw ) == false ))
					{
						feVM.change_selection( step, false );
						redraw=true;
					}
				}
			}
			else
			{
				move_state = FeInputMap::LAST_COMMAND;
				move_last_triggered = 0;

				feVM.on_end_navigation();
				redraw=true;
			}
		}

		if ( feVM.on_tick() )
			redraw=true;

		if ( feVM.video_tick() )
			redraw=true;

		if ( feVM.saver_activation_check() )
			soundsys.sound_event( FeInputMap::ScreenSaver );

		if ( redraw )
		{
			// begin drawing
			window.clear();
			window.draw( feVM );
			window.display();
			redraw=false;
		}
		else
			sf::sleep( sf::milliseconds( 30 ) );

		soundsys.tick();
	}

	window.on_exit();
	feVM.on_stop_frontend();

	if ( window.isOpen() )
		window.close();

	FeRomListSorter::clear_title_rex();

	soundsys.stop();
	feSettings.save_state();

	return 0;
}
static as_bool download_complete (ASDownload *dl)
{
	char *prefixed_name;

	AS_DBG_1 ("Completed download \"%s\"", dl->filename);

	/* close fd */
	if (dl->fp)
	{
		fclose (dl->fp);
		dl->fp = NULL;
	}

	/* rename complete file to not include the prefix. */
	prefixed_name = as_get_filename (dl->path);

	if (strncmp (prefixed_name, AS_DOWNLOAD_INCOMPLETE_PREFIX,
	             strlen (AS_DOWNLOAD_INCOMPLETE_PREFIX)) == 0)
	{
		char *completed_path, *uniq_path, *dir;

		/* construct path without ___ARESTRA___ prefix */
		dir = gift_strndup (dl->path, prefixed_name - dl->path);
		completed_path = stringf_dup ("%s%s", dir ? dir : "",
		                        prefixed_name + strlen (AS_DOWNLOAD_INCOMPLETE_PREFIX));
		free (dir);

		if ((uniq_path = get_available_filename (completed_path)))
		{
			if (rename (dl->path, uniq_path) >= 0)
			{
				AS_DBG_2 ("Moved complete file \"%s\" to \"%s\"",
				          dl->path, uniq_path);

				/* update download filename */
				free (dl->path);
				dl->path = uniq_path;
				dl->filename = as_get_filename (dl->path);
			}
			else
			{
				AS_ERR_2 ("Renaming file from \"%s\" to \"%s\" failed.",
				          dl->path, uniq_path);
				free (uniq_path);
			}
		}
		else
		{
			AS_ERR_1 ("No unique name found for \"%s\"", dl->path);
		}
	}
	else
	{
		AS_WARN_1 ("Complete file \"%s\" has no prefix. No renaming performed.",
		           dl->path);
	}

	/* raise callback */
	if (!download_set_state (dl, DOWNLOAD_COMPLETE, TRUE))
		return FALSE;

	return TRUE;
}
Exemple #3
0
bool FeSettings::build_romlist( const std::vector< FeImportTask > &task_list,
						const std::string &output_name,
						FeFilter &filter,
						bool full )
{
	FeRomInfoListType total_romlist;
	std::string best_name, list_name, path;

	for ( std::vector<FeImportTask>::const_iterator itr=task_list.begin();
			itr < task_list.end(); ++itr )
	{
		if ( (*itr).task_type == FeImportTask::BuildRomlist )
		{
			// Build romlist task
			std::cout << "*** Generating Collection/Rom List" << std::endl;

			FeEmulatorInfo *emu = m_rl.get_emulator( (*itr).emulator_name );
			if ( emu == NULL )
			{
				std::cout << "Error: Invalid -build-rom-list target: " <<  (*itr).emulator_name
					<< std::endl;
			}
			else
			{
				FeRomInfoListType romlist;

				best_name = emu->get_info( FeEmulatorInfo::Name );

				FeImporterContext ctx( *emu, romlist );
				build_basic_romlist( ctx );

				apply_xml_import( ctx );
				apply_import_extras( ctx );

				apply_emulator_name( best_name, romlist );
				total_romlist.splice( total_romlist.end(), romlist );
			}
		}
		else if ( (*itr).task_type == FeImportTask::ImportRomlist )
		{
			// import romlist from file task
			std::cout << "*** Importing Collection/Rom List" << std::endl;

			FeRomInfoListType romlist;
			std::string emu_name;

			if ( (*itr).emulator_name.empty() )
			{
				// deduce the emulator name from the filename provided
				size_t my_start = (*itr).file_name.find_last_of( "\\/" );
				if ( my_start == std::string::npos ) // if there is no / we start at the beginning
					my_start = 0;
				else
					my_start += 1;

				size_t my_end = (*itr).file_name.find_last_of( "." );
				if ( my_end != std::string::npos )
					emu_name = (*itr).file_name.substr( my_start, my_end - my_start  );
			}
			else
				emu_name = (*itr).emulator_name;

			best_name = emu_name;

			if ( tail_compare( (*itr).file_name, ".txt" ) )
			{
				// Attract-Mode format list
				//
				FeRomList temp_list( m_config_path );
				temp_list.load_from_file( (*itr).file_name, ";" );

				FeRomInfoListType &entries = temp_list.get_list();

				for ( FeRomInfoListType::iterator itr = entries.begin(); itr != entries.end(); ++itr )
					romlist.push_back( *itr );
			}
			else if ( tail_compare( (*itr).file_name, ".lst" ) )
			{
				// Mamewah/Wahcade! format list
				//
				import_mamewah( (*itr).file_name, emu_name, romlist );
			}
			else if ( tail_compare( (*itr).file_name, ".xml" ) )
			{
				// HyperSpin format list
				//
				FeHyperSpinXMLParser my_parser( romlist );
				if ( my_parser.parse( (*itr).file_name ) )
					apply_emulator_name( emu_name, romlist );
			}
			else
			{
				std::cerr << "Error: Unsupported --import-rom-list file: "
					<<  (*itr).file_name << std::endl;
			}

			std::cout << "[Import " << (*itr).file_name << "] - Imported " << romlist.size() << " entries."
				<< std::endl;

			FeEmulatorInfo *emu = m_rl.get_emulator( emu_name );
			if ( emu == NULL )
			{
				std::cout << "Warning: The emulator specified with --import-rom-list was not found: "
					<<  emu_name << std::endl;
			}
			else
			{
				FeImporterContext ctx( *emu, romlist );
				apply_import_extras( ctx );
			}

			total_romlist.splice( total_romlist.end(), romlist );
		}
		else // scrape artwork
		{
			FeEmulatorInfo *emu = m_rl.get_emulator( (*itr).emulator_name );
			if ( emu == NULL )
				return false;

			std::cout << "*** Scraping artwork for: " << (*itr).emulator_name << std::endl;

			FeRomInfoListType romlist;
			std::string fn = get_config_dir() + FE_ROMLIST_SUBDIR + (*itr).emulator_name + FE_ROMLIST_FILE_EXTENSION;

			FeImporterContext ctx( *emu, romlist );
			if ( file_exists( fn ) )
			{
				FeRomList loader( get_config_dir() );
				loader.load_from_file( fn, ";" );
				ctx.romlist.swap( loader.get_list() );
			}
			else
			{
				build_basic_romlist( ctx );
				apply_xml_import( ctx );
			}

			ctx.scrape_art = true;
			confirm_directory( get_config_dir(), FE_SCRAPER_SUBDIR );

			// do the mamedb scraper first (which only does anything for mame) followed
			// by the more general thegamesdb scraper.
			mamedb_scraper( ctx );
			thegamesdb_scraper( ctx );

			std::cout << "*** Scraping done." << std::endl;
		}
	}

	// return now if all we did was scrape artwork
	if ( total_romlist.empty() )
		return true;

	total_romlist.sort( FeRomListSorter() );

	// strip duplicate entries
	std::cout << " - Removing any duplicate entries..." << std::endl;
	total_romlist.unique();

	// Apply the specified filter
	if ( filter.get_rule_count() > 0 )
	{
		std::cout << " - Applying filter..." << std::endl;
		filter.init();

		FeRomInfoListType::iterator last_it=total_romlist.begin();
		for ( FeRomInfoListType::iterator it=total_romlist.begin(); it!=total_romlist.end(); )
		{
			if ( filter.apply_filter( *it ) )
			{
				if ( last_it != it )
					it = total_romlist.erase( last_it, it );
				else
					++it;

				last_it = it;
			}
			else
				++it;
		}

		if ( last_it != total_romlist.end() )
			total_romlist.erase( last_it, total_romlist.end() );
	}

	if ( task_list.size() > 1 )
		best_name = "multi";

	path = get_config_dir();
	confirm_directory( path, FE_ROMLIST_SUBDIR );

	path += FE_ROMLIST_SUBDIR;

	// if we weren't given a specific output name, then we come up with a name
	// that doesn't exist already
	//
	if ( output_name.empty() )
		get_available_filename( path, best_name, FE_ROMLIST_FILE_EXTENSION, list_name );
	else
		list_name = path + output_name + FE_ROMLIST_FILE_EXTENSION;

	write_romlist( list_name, total_romlist );

	return true;
}
/* Start download using hash, filesize and save name. */
as_bool as_download_start (ASDownload *dl, ASHash *hash, size_t filesize,
                           const char *save_path)
{
	ASDownChunk *chunk;
	char *incomplete, *dir;

	if (dl->state != DOWNLOAD_NEW)
	{
		assert (dl->state == DOWNLOAD_NEW);
		return FALSE;
	}

	if (!hash || !save_path || filesize == 0)
	{
		assert (hash);
		assert (save_path);
		assert (filesize > 0);
		return FALSE;
	}

	/* create incomplete file path */
	dir = gift_strndup (save_path, as_get_filename (save_path) - save_path);
	incomplete = stringf_dup ("%s%s%s", dir ? dir : "", AS_DOWNLOAD_INCOMPLETE_PREFIX,
	                          as_get_filename (save_path));
	free (dir);

	/* find a name which is not used already */
	if (!(dl->path = get_available_filename (incomplete)))
	{
		AS_ERR_1 ("Couldn't find available file name for download \"%s\"",
		          dl->path);
		free (incomplete);
		return FALSE;
	}
	free (incomplete);

	/* set filename after __ARESTRA__prefix */
	dl->filename = as_get_filename (dl->path);
	if (strncmp (dl->filename, AS_DOWNLOAD_INCOMPLETE_PREFIX,
	             strlen (AS_DOWNLOAD_INCOMPLETE_PREFIX)) == 0)
		dl->filename += strlen (AS_DOWNLOAD_INCOMPLETE_PREFIX);

	/* open file */
	if (!(dl->fp = fopen (dl->path, "w+b")))
	{
		AS_ERR_1 ("Unable to open download file \"%s\" for writing",
		          dl->path);
		free (dl->path);
		dl->path = NULL;
		dl->filename = NULL;
		return FALSE;
	}

	/* create one initial chunk for entire file */
	dl->size = filesize;

	if (!(chunk = as_downchunk_create (0, dl->size)))
	{
		AS_ERR_1 ("Couldn't create initial chunk (0,%u)", dl->size);
		free (dl->path);
		dl->path = NULL;
		dl->filename = NULL;
		dl->size = 0;
		return FALSE;
	}

	dl->chunks = list_prepend (dl->chunks, chunk);

	/* copy hash */
	dl->hash = as_hash_copy (hash);

	/* raise callback */
	if (!download_set_state (dl, DOWNLOAD_ACTIVE, TRUE))
		return FALSE;

	/* Immediately save state data so we have something to recover from. */
	if (!as_downstate_save (dl))
	{
		AS_ERR_1 ("Failed to write state data for \"%s\". Pausing.",
		          dl->filename);
		as_download_pause (dl);
		/* return TRUE because the download setup has succeeded */
		return TRUE;
	}

	/* start things off if we are still in active state */
	if (dl->state == DOWNLOAD_ACTIVE)
		download_maintain (dl);

	return TRUE;
}