Esempio n. 1
0
/*	write statefile
 */
void BarSettingsWrite (PianoStation_t *station, BarSettings_t *settings) {
	char path[PATH_MAX];
	FILE *fd;

	assert (settings != NULL);

	BarGetXdgConfigDir (PACKAGE "/state", path, sizeof (path));
	if ((fd = fopen (path, "w")) == NULL) {
		return;
	}

	fputs ("# do not edit this file\n", fd);
	fprintf (fd, "volume = %i\n", settings->volume);
	if (station != NULL) {
		fprintf (fd, "autostart_station = %s\n", station->id);
	}

	fclose (fd);
}
Esempio n. 2
0
/*	write statefile
 */
void BarSettingsWrite (PianoStation_t *station, BarSettings_t *settings) {
	FILE *fd;

	assert (settings != NULL);

	char * const path = BarGetXdgConfigDir (PACKAGE "/state");
	assert (path != NULL);
	if ((fd = fopen (path, "w")) == NULL) {
		free (path);
		return;
	}

	fputs ("# do not edit this file\n", fd);
	fprintf (fd, "volume = %i\n", settings->volume);
	if (station != NULL) {
		fprintf (fd, "autostart_station = %s\n", station->id);
	}

	fclose (fd);
	free (path);
}
Esempio n. 3
0
/*	read app settings from file; format is: key = value\n
 *	@param where to save these settings
 *	@return nothing yet
 */
void BarSettingsRead (BarSettings_t *settings) {
	char configfile[MAXPATHLEN], key[256], val[256];
	FILE *configfd = NULL;
	static const char *formatMsgPrefix = "format_msg_";

	assert (sizeof (settings->keys) / sizeof (*settings->keys) ==
			sizeof (dispatchActions) / sizeof (*dispatchActions));

	/* apply defaults */
	settings->audioQuality = PIANO_AQ_HIGH;
	settings->autoselect = true;
	settings->history = 5;
	settings->volume = 0;
	settings->sortOrder = BAR_SORT_NAME_AZ;
	settings->loveIcon = strdup (" <3");
	settings->banIcon = strdup (" </3");
	settings->atIcon = strdup (" @ ");
	settings->npSongFormat = strdup ("\"%t\" by \"%a\" on \"%l\"%r%@%s");
	settings->npStationFormat = strdup ("Station \"%n\" (%i)");
	settings->listSongFormat = strdup ("%i) %a - %t%r");
	settings->rpcHost = strdup (PIANO_RPC_HOST);
	settings->partnerUser = strdup ("android");
	settings->partnerPassword = strdup ("AC7IBG09A3DTSYM4R41UJWL07VLN8JI7");
	settings->device = strdup ("android-generic");
	settings->inkey = strdup ("R=U!LH$O2B#");
	settings->outkey = strdup ("6#26FRL$ZWD");
	settings->fifo = malloc (PATH_MAX * sizeof (*settings->fifo));
	BarGetXdgConfigDir (PACKAGE "/ctl", settings->fifo, PATH_MAX);
	memcpy (settings->tlsFingerprint, "\xA2\xA0\xBE\x8A\x37\x92\x39\xAE"
			"\x2B\x2E\x71\x4C\x56\xB3\x8B\xC1\x2A\x9B\x4B\x77",
			sizeof (settings->tlsFingerprint));

	settings->msgFormat[MSG_NONE].prefix = NULL;
	settings->msgFormat[MSG_NONE].postfix = NULL;
	settings->msgFormat[MSG_INFO].prefix = strdup ("(i) ");
	settings->msgFormat[MSG_INFO].postfix = NULL;
	settings->msgFormat[MSG_PLAYING].prefix = strdup ("|>  ");
	settings->msgFormat[MSG_PLAYING].postfix = NULL;
	settings->msgFormat[MSG_TIME].prefix = strdup ("#   ");
	settings->msgFormat[MSG_TIME].postfix = NULL;
	settings->msgFormat[MSG_ERR].prefix = strdup ("/!\\ ");
	settings->msgFormat[MSG_ERR].postfix = NULL;
	settings->msgFormat[MSG_QUESTION].prefix = strdup ("[?] ");
	settings->msgFormat[MSG_QUESTION].postfix = NULL;
	settings->msgFormat[MSG_LIST].prefix = strdup ("\t");
	settings->msgFormat[MSG_LIST].postfix = NULL;

	settings->useSpaces = false;
	settings->embedCover = true;

	for (size_t i = 0; i < BAR_KS_COUNT; i++) {
		settings->keys[i] = dispatchActions[i].defaultKey;
	}

	BarGetXdgConfigDir (PACKAGE "/config", configfile, sizeof (configfile));

	/* read config file */
	if ((configfd = fopen (configfile, "r")) != NULL) {
	while (1) {
		char lwhite, rwhite;
		int scanRet = fscanf (configfd, "%255s%c=%c%255[^\n]", key, &lwhite, &rwhite, val);
		if (scanRet == EOF) {
			break;
		} else if (scanRet != 4 || lwhite != ' ' || rwhite != ' ') {
			/* invalid config line */
			continue;
		}
		if (streq ("control_proxy", key)) {
			settings->controlProxy = strdup (val);
		} else if (streq ("proxy", key)) {
			settings->proxy = strdup (val);
		} else if (streq ("user", key)) {
			settings->username = strdup (val);
		} else if (streq ("password", key)) {
			settings->password = strdup (val);
		} else if (streq ("rpc_host", key)) {
			free (settings->rpcHost);
			settings->rpcHost = strdup (val);
		} else if (streq ("partner_user", key)) {
			free (settings->partnerUser);
			settings->partnerUser = strdup (val);
		} else if (streq ("partner_password", key)) {
			free (settings->partnerPassword);
			settings->partnerPassword = strdup (val);
		} else if (streq ("device", key)) {
			free (settings->device);
			settings->device = strdup (val);
		} else if (streq ("encrypt_password", key)) {
			free (settings->outkey);
			settings->outkey = strdup (val);
		} else if (streq ("decrypt_password", key)) {
			free (settings->inkey);
			settings->inkey = strdup (val);
		} else if (memcmp ("act_", key, 4) == 0) {
			size_t i;
			/* keyboard shortcuts */
			for (i = 0; i < BAR_KS_COUNT; i++) {
				if (streq (dispatchActions[i].configKey, key)) {
					if (streq (val, "disabled")) {
						settings->keys[i] = BAR_KS_DISABLED;
					} else {
						settings->keys[i] = val[0];
					}
				}
			}
		} else if (streq ("audio_format", key)) {
			if (streq (val, "aacplus")) {
				settings->audioFormat = PIANO_AF_AACPLUS;
			} else if (streq (val, "mp3")) {
				settings->audioFormat = PIANO_AF_MP3;
			} else if (streq (val, "mp3-hifi")) {
				settings->audioFormat = PIANO_AF_MP3_HI;
			}
		} else if (streq ("audio_quality", key)) {
			if (streq (val, "low")) {
				settings->audioQuality = PIANO_AQ_LOW;
			} else if (streq (val, "medium")) {
				settings->audioQuality = PIANO_AQ_MEDIUM;
			} else if (streq (val, "high")) {
				settings->audioQuality = PIANO_AQ_HIGH;
			}
		} else if (streq ("autostart_station", key)) {
			settings->autostartStation = strdup (val);
		} else if (streq ("event_command", key)) {
			settings->eventCmd = strdup (val);
		} else if (streq ("history", key)) {
			settings->history = atoi (val);
			} else if (streq ("audio_file_dir", key)) {
				free (settings->audioFileDir);
				settings->audioFileDir = strdup(val);
			} else if (streq ("audio_file_name", key)) {
				free (settings->audioFileName);
				settings->audioFileName = strdup(val);
			} else if (streq ("use_spaces", key)) {
				if (streq ("true", val)) {
					settings->useSpaces = true;
				}
			} else if (streq ("embed_cover", key)) {
				if (!streq ("true", val)) {
					settings->embedCover = false;
				}
			} else if (streq ("autostart_station", key)) {
				free (settings->autostartStation);
				settings->autostartStation = strdup (val);
			} else if (streq ("event_command", key)) {
				free (settings->eventCmd);
				settings->eventCmd = strdup (val);
			} else if (streq ("history", key)) {
				settings->history = atoi (val);
			} else if (streq ("sort", key)) {
				size_t i;
				static const char *mapping[] = {"name_az",
						"name_za",
						"quickmix_01_name_az",
						"quickmix_01_name_za",
						"quickmix_10_name_az",
						"quickmix_10_name_za",
						};
				for (i = 0; i < BAR_SORT_COUNT; i++) {
					if (streq (mapping[i], val)) {
						settings->sortOrder = i;
						break;
					}
				}
			} else if (streq ("love_icon", key)) {
				free (settings->loveIcon);
				settings->loveIcon = strdup (val);
			} else if (streq ("ban_icon", key)) {
				free (settings->banIcon);
				settings->banIcon = strdup (val);
			} else if (streq ("at_icon", key)) {
			free (settings->atIcon);
			settings->atIcon = strdup (val);
		} else if (streq ("volume", key)) {
			settings->volume = atoi (val);
		} else if (streq ("format_nowplaying_song", key)) {
			free (settings->npSongFormat);
			settings->npSongFormat = strdup (val);
		} else if (streq ("format_nowplaying_station", key)) {
			free (settings->npStationFormat);
			settings->npStationFormat = strdup (val);
		} else if (streq ("format_list_song", key)) {
			free (settings->listSongFormat);
			settings->listSongFormat = strdup (val);
		} else if (streq ("fifo", key)) {
			free (settings->fifo);
			settings->fifo = strdup (val);
		} else if (streq ("autoselect", key)) {
			settings->autoselect = atoi (val);
		} else if (streq ("tls_fingerprint", key)) {
			/* expects 40 byte hex-encoded sha1 */
			if (strlen (val) == 40) {
				for (size_t i = 0; i < 20; i++) {
					char hex[3];
					memcpy (hex, &val[i*2], 2);
					hex[2] = '\0';
					settings->tlsFingerprint[i] = strtol (hex, NULL, 16);
				}
			}
		} else if (strncmp (formatMsgPrefix, key,
				strlen (formatMsgPrefix)) == 0) {
			static const char *mapping[] = {"none", "info", "nowplaying",
					"time", "err", "question", "list"};
			const char *typeStart = key + strlen (formatMsgPrefix);
			for (size_t i = 0; i < sizeof (mapping) / sizeof (*mapping); i++) {
				if (streq (typeStart, mapping[i])) {
					const char *formatPos = strstr (val, "%s");
					
						/* keep default if there is no format character */
						if (formatPos != NULL) {
							BarMsgFormatStr_t *format = &settings->msgFormat[i];

							free (format->prefix);
							free (format->postfix);

							const size_t prefixLen = formatPos - val;
							format->prefix = calloc (prefixLen + 1,
									sizeof (*format->prefix));
							memcpy (format->prefix, val, prefixLen);

							const size_t postfixLen = strlen (val) -
									(formatPos-val) - 2;
							format->postfix = calloc (postfixLen + 1,
									sizeof (*format->postfix));
							memcpy (format->postfix, formatPos+2, postfixLen);
						}
						break;
					}
				}
			}
		}
	}

	/* check environment variable if proxy is not set explicitly */
	if (settings->proxy == NULL) {
		char *tmpProxy = getenv ("http_proxy");
		if (tmpProxy != NULL && strlen (tmpProxy) > 0) {
			settings->proxy = strdup (tmpProxy);
		}
	}

	/* Use a local ./mp3 directory if no audio file directory was set. */
	if (settings->audioFileDir == NULL) {
		settings->audioFileDir = strdup(BAR_DEFAULT_AUDIO_FILE_DIR);
	}

	/* Use the default file name if none was set. */
	if (settings->audioFileName == NULL) {
		settings->audioFileName = strdup(BAR_DEFAULT_AUDIO_FILE_NAME);
	}

	if (configfd != NULL) {
		fclose (configfd);
	}

	return;
}
Esempio n. 4
0
/*	read app settings from file; format is: key = value\n
 *	@param where to save these settings
 *	@return nothing yet
 */
void BarSettingsRead (BarSettings_t *settings) {
	/* FIXME: what is the max length of a path? */
	char configfile[1024], key[256], val[256];
	FILE *configfd;
	/* _must_ have same order as in BarKeyShortcutId_t */
	static const char defaultKeys[] = {'?', '+', '-', 'a', 'c', 'd', 'e', 'g',
			'h', 'i', 'j', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'x', '$',
			'b',
			};
	static const char *shortcutFileKeys[] = {
			"act_help", "act_songlove", "act_songban", "act_stationaddmusic",
			"act_stationcreate", "act_stationdelete", "act_songexplain",
			"act_stationaddbygenre", "act_history", "act_songinfo",
			"act_addshared", "act_songmove", "act_songnext", "act_songpause",
			"act_quit", "act_stationrename", "act_stationchange",
			"act_songtired", "act_upcoming", "act_stationselectquickmix",
			"act_debug", "act_bookmark",
			};

	/* apply defaults */
	#ifdef ENABLE_FAAD
	settings->audioFormat = PIANO_AF_AACPLUS;
	#else
		#ifdef ENABLE_MAD
		settings->audioFormat = PIANO_AF_MP3;
		#endif
	#endif
	settings->history = 5;
	settings->sortOrder = BAR_SORT_NAME_AZ;
	memcpy (settings->keys, defaultKeys, sizeof (defaultKeys));
	settings->loveIcon = strdup ("<3");
	settings->banIcon = strdup ("</3");

	BarGetXdgConfigDir (PACKAGE "/config", configfile, sizeof (configfile));
	if ((configfd = fopen (configfile, "r")) == NULL) {
		return;
	}

	/* read config file */
	while (1) {
		int scanRet = fscanf (configfd, "%255s = %255[^\n]", key, val);
		if (scanRet == EOF) {
			break;
		} else if (scanRet != 2) {
			/* invalid config line */
			continue;
		}
		if (streq ("control_proxy", key)) {
			settings->controlProxy = strdup (val);
		} else if (streq ("proxy", key)) {
			settings->proxy = strdup (val);
		} else if (streq ("user", key)) {
			settings->username = strdup (val);
		} else if (streq ("password", key)) {
			settings->password = strdup (val);
		} else if (strcmp ("lastfm_user", key) == 0) {
			settings->lastfmUser = strdup (val);
		} else if (strcmp ("lastfm_password", key) == 0) {
			settings->lastfmPassword = strdup (val);
		} else if (strcmp ("lastfm_scrobble_percent", key) == 0) {
			settings->lastfmScrobblePercent = atoi (val);
		} else if (memcmp ("act_", key, 4) == 0) {
			size_t i;
			/* keyboard shortcuts */
			for (i = 0; i < BAR_KS_COUNT; i++) {
				if (streq (shortcutFileKeys[i], key)) {
					settings->keys[i] = val[0];
					break;
				}
			}
		} else if (streq ("audio_format", key)) {
			if (streq (val, "aacplus")) {
				settings->audioFormat = PIANO_AF_AACPLUS;
			} else if (streq (val, "mp3")) {
				settings->audioFormat = PIANO_AF_MP3;
			} else if (streq (val, "mp3-hifi")) {
				settings->audioFormat = PIANO_AF_MP3_HI;
			}
		} else if (streq ("autostart_station", key)) {
			settings->autostartStation = strdup (val);
		} else if (streq ("event_command", key)) {
			settings->eventCmd = strdup (val);
		} else if (streq ("history", key)) {
			settings->history = atoi (val);
		} else if (streq ("sort", key)) {
			size_t i;
			static const char *mapping[] = {"name_az",
					"name_za",
					"quickmix_01_name_az",
					"quickmix_01_name_za",
					"quickmix_10_name_az",
					"quickmix_10_name_za",
					};
			for (i = 0; i < BAR_SORT_COUNT; i++) {
				if (streq (mapping[i], val)) {
					settings->sortOrder = i;
					break;
				}
			}
		} else if (streq ("love_icon", key)) {
			free (settings->loveIcon);
			settings->loveIcon = strdup (val);
		} else if (streq ("ban_icon", key)) {
			free (settings->banIcon);
			settings->banIcon = strdup (val);
		}
	}

	/* some checks */
	/* last.fm requests tracks to be played at least 50% */
	if (settings->lastfmScrobblePercent < 50 ||
			settings->lastfmScrobblePercent > 100) {
		settings->lastfmScrobblePercent = 50;
	}

	/* only scrobble tracks if username and password are set */
	if (settings->lastfmUser != NULL && settings->lastfmPassword != NULL) {
		settings->enableScrobbling = 1;
	}
	/* check environment variable if proxy is not set explicitly */
	if (settings->proxy == NULL) {
		char *tmpProxy = getenv ("http_proxy");
		if (tmpProxy != NULL && strlen (tmpProxy) > 0) {
			settings->proxy = strdup (tmpProxy);
		}
	}

	fclose (configfd);
}
Esempio n. 5
0
int main (int argc, char **argv) {
	static BarApp_t app;
	pthread_t playerThread;
	/* FIXME: max path length? */
	char ctlPath[1024];
	FILE *ctlFd = NULL;
	struct timeval selectTimeout;
	int maxFd, selectFds[2];
	fd_set readSet, readSetCopy;
	char buf = '\0';
	/* terminal attributes _before_ we started messing around with ~ECHO */
	struct termios termOrig;

	memset (&app, 0, sizeof (app));

	/* save terminal attributes, before disabling echoing */
	BarTermSave (&termOrig);

	BarTermSetEcho (0);
	BarTermSetBuffer (0);
	/* init some things */
	ao_initialize ();
	PianoInit (&app.ph);

	WaitressInit (&app.waith);
	strncpy (app.waith.host, PIANO_RPC_HOST, sizeof (app.waith.host)-1);
	strncpy (app.waith.port, PIANO_RPC_PORT, sizeof (app.waith.port)-1);

	BarSettingsInit (&app.settings);
	BarSettingsRead (&app.settings);

	BarUiMsg (MSG_NONE, "Welcome to " PACKAGE "! Press %c for a list of commands.\n",
			app.settings.keys[BAR_KS_HELP]);

	/* init fds */
	FD_ZERO(&readSet);
	selectFds[0] = fileno (stdin);
	FD_SET(selectFds[0], &readSet);
	maxFd = selectFds[0] + 1;

	BarGetXdgConfigDir (PACKAGE "/ctl", ctlPath, sizeof (ctlPath));
	/* FIXME: why is r_+_ required? */
	ctlFd = fopen (ctlPath, "r+");
	if (ctlFd != NULL) {
		selectFds[1] = fileno (ctlFd);
		FD_SET(selectFds[1], &readSet);
		/* assuming ctlFd is always > stdin */
		maxFd = selectFds[1] + 1;
		BarUiMsg (MSG_INFO, "Control fifo at %s opened\n", ctlPath);
	}

	if (app.settings.username == NULL) {
		char nameBuf[100];
		BarUiMsg (MSG_QUESTION, "Username: "******"Password: "******"Login... ");
		if (!BarUiPianoCall (&app.ph, PIANO_REQUEST_LOGIN, &app.waith,
				&reqData, &pRet, &wRet)) {
			BarTermRestore (&termOrig);
			return 0;
		}
	}

	{
		PianoReturn_t pRet;
		WaitressReturn_t wRet;

		BarUiMsg (MSG_INFO, "Get stations... ");
		if (!BarUiPianoCall (&app.ph, PIANO_REQUEST_GET_STATIONS, &app.waith,
				NULL, &pRet, &wRet)) {
			BarTermRestore (&termOrig);
			return 0;
		}
	}

	/* try to get autostart station */
	if (app.settings.autostartStation != NULL) {
		app.curStation = PianoFindStationById (app.ph.stations,
				app.settings.autostartStation);
		if (app.curStation == NULL) {
			BarUiMsg (MSG_ERR, "Error: Autostart station not found.\n");
		}
	}
	/* no autostart? ask the user */
	if (app.curStation == NULL) {
		app.curStation = BarUiSelectStation (&app.ph, "Select station: ",
				app.settings.sortOrder, stdin);
	}
	if (app.curStation != NULL) {
		BarUiPrintStation (app.curStation);
	}

	/* little hack, needed to signal: hey! we need a playlist, but don't
	 * free anything (there is nothing to be freed yet) */
	memset (&app.player, 0, sizeof (app.player));

	while (!app.doQuit) {
		/* song finished playing, clean up things/scrobble song */
		if (app.player.mode == PLAYER_FINISHED_PLAYBACK) {
			BarUiStartEventCmd (&app.settings, "songfinish", app.curStation,
					app.playlist, &app.player, PIANO_RET_OK, WAITRESS_RET_OK);
			/* FIXME: pthread_join blocks everything if network connection
			 * is hung up e.g. */
			void *threadRet;
			pthread_join (playerThread, &threadRet);
			/* don't continue playback if thread reports error */
			if (threadRet != (void *) PLAYER_RET_OK) {
				app.curStation = NULL;
			}
			memset (&app.player, 0, sizeof (app.player));
		}

		/* check whether player finished playing and start playing new
		 * song */
		if (app.player.mode >= PLAYER_FINISHED_PLAYBACK ||
				app.player.mode == PLAYER_FREED) {
			if (app.curStation != NULL) {
				/* what's next? */
				if (app.playlist != NULL) {
					if (app.settings.history != 0) {
						/* prepend song to history list */
						PianoSong_t *tmpSong = app.songHistory;
						app.songHistory = app.playlist;
						/* select next song */
						app.playlist = app.playlist->next;
						app.songHistory->next = tmpSong;

						/* limit history's length */
						/* start with 1, so we're stopping at n-1 and have the
						 * chance to set ->next = NULL */
						unsigned int i = 1;
						tmpSong = app.songHistory;
						while (i < app.settings.history && tmpSong != NULL) {
							tmpSong = tmpSong->next;
							++i;
						}
						/* if too many songs in history... */
						if (tmpSong != NULL) {
							PianoSong_t *delSong = tmpSong->next;
							tmpSong->next = NULL;
							if (delSong != NULL) {
								PianoDestroyPlaylist (delSong);
							}
						}
					} else {
						/* don't keep history */
						app.playlist = app.playlist->next;
					}
				}
				if (app.playlist == NULL) {
					PianoReturn_t pRet;
					WaitressReturn_t wRet;
					PianoRequestDataGetPlaylist_t reqData;
					reqData.station = app.curStation;
					reqData.format = app.settings.audioFormat;

					BarUiMsg (MSG_INFO, "Receiving new playlist... ");
					if (!BarUiPianoCall (&app.ph, PIANO_REQUEST_GET_PLAYLIST,
							&app.waith, &reqData, &pRet, &wRet)) {
						app.curStation = NULL;
					} else {
						app.playlist = reqData.retPlaylist;
						if (app.playlist == NULL) {
							BarUiMsg (MSG_INFO, "No tracks left.\n");
							app.curStation = NULL;
						}
					}
					BarUiStartEventCmd (&app.settings, "stationfetchplaylist",
							app.curStation, app.playlist, &app.player, pRet,
							wRet);
				}
				/* song ready to play */
				if (app.playlist != NULL) {
					BarUiPrintSong (app.playlist, app.curStation->isQuickMix ?
							PianoFindStationById (app.ph.stations,
							app.playlist->stationId) : NULL);

					if (app.playlist->audioUrl == NULL) {
						BarUiMsg (MSG_ERR, "Invalid song url.\n");
					} else {
						/* setup player */
						memset (&app.player, 0, sizeof (app.player));

						WaitressInit (&app.player.waith);
						WaitressSetUrl (&app.player.waith, app.playlist->audioUrl);

						/* set up global proxy, player is NULLed on songfinish */
						if (app.settings.proxy != NULL) {
							char tmpPath[2];
							WaitressSplitUrl (app.settings.proxy,
									app.player.waith.proxyHost,
									sizeof (app.player.waith.proxyHost),
									app.player.waith.proxyPort,
									sizeof (app.player.waith.proxyPort), tmpPath,
									sizeof (tmpPath));
						}

						app.player.gain = app.playlist->fileGain;
						app.player.audioFormat = app.playlist->audioFormat;
			
						/* throw event */
						BarUiStartEventCmd (&app.settings, "songstart",
								app.curStation, app.playlist, &app.player,
								PIANO_RET_OK, WAITRESS_RET_OK);

						/* prevent race condition, mode must _not_ be FREED if
						 * thread has been started */
						app.player.mode = PLAYER_STARTING;
						/* start player */
						pthread_create (&playerThread, NULL, BarPlayerThread,
								&app.player);
					} /* end if audioUrl == NULL */
				} /* end if playlist != NULL */
			} /* end if curStation != NULL */
		}

		/* select modifies its arguments => copy the set */
		memcpy (&readSetCopy, &readSet, sizeof (readSet));
		selectTimeout.tv_sec = 1;
		selectTimeout.tv_usec = 0;

		/* in the meantime: wait for user actions */
		if (select (maxFd, &readSetCopy, NULL, NULL, &selectTimeout) > 0) {
			FILE *curFd = NULL;

			if (FD_ISSET(selectFds[0], &readSetCopy)) {
				curFd = stdin;
			} else if (FD_ISSET(selectFds[1], &readSetCopy)) {
				curFd = ctlFd;
			}
			buf = fgetc (curFd);

			size_t i;
			for (i = 0; i < BAR_KS_COUNT; i++) {
				if (app.settings.keys[i] == buf) {
					static const BarKeyShortcutFunc_t idToF[] = {BarUiActHelp,
							BarUiActLoveSong, BarUiActBanSong,
							BarUiActAddMusic, BarUiActCreateStation,
							BarUiActDeleteStation, BarUiActExplain,
							BarUiActStationFromGenre, BarUiActHistory,
							BarUiActSongInfo, BarUiActAddSharedStation,
							BarUiActMoveSong, BarUiActSkipSong, BarUiActPause,
							BarUiActQuit, BarUiActRenameStation,
							BarUiActSelectStation, BarUiActTempBanSong,
							BarUiActPrintUpcoming, BarUiActSelectQuickMix,
							BarUiActDebug, BarUiActBookmark};
					idToF[i] (&app, curFd);
					break;
				}
			}
		}

		/* show time */
		if (app.player.mode >= PLAYER_SAMPLESIZE_INITIALIZED &&
				app.player.mode < PLAYER_FINISHED_PLAYBACK) {
			/* Ugly: songDuration is unsigned _long_ int! Lets hope this won't
			 * overflow */
			int songRemaining = (signed long int) (app.player.songDuration -
					app.player.songPlayed) / BAR_PLAYER_MS_TO_S_FACTOR;
			char pos = 0;
			if (songRemaining < 0) {
				/* Use plus sign if song is longer than expected */
				pos = 1;
				songRemaining = -songRemaining;
			}
			BarUiMsg (MSG_TIME, "%c%02i:%02i/%02i:%02i\r", (pos ? '+' : '-'),
					songRemaining / 60, songRemaining % 60,
					app.player.songDuration / BAR_PLAYER_MS_TO_S_FACTOR / 60,
					app.player.songDuration / BAR_PLAYER_MS_TO_S_FACTOR % 60);
		}
	}

	/* destroy everything (including the world...) */
	if (app.player.mode != PLAYER_FREED) {
		pthread_join (playerThread, NULL);
	}
	if (ctlFd != NULL) {
		fclose (ctlFd);
	}
	PianoDestroy (&app.ph);
	PianoDestroyPlaylist (app.songHistory);
	PianoDestroyPlaylist (app.playlist);
	ao_shutdown();
	BarSettingsDestroy (&app.settings);

	/* restore terminal attributes, zsh doesn't need this, bash does... */
	BarTermRestore (&termOrig);

	return 0;
}
Esempio n. 6
0
/*	read app settings from file; format is: key = value\n
 *	@param where to save these settings
 *	@return nothing yet
 */
void BarSettingsRead (BarSettings_t *settings) {
	char * const configfiles[] = { PACKAGE_STATE, PACKAGE_CONFIG };
	char * const userhome = BarSettingsGetHome ();
	assert (userhome != NULL);
	/* set xdg config path (if not set) */
	char * const defaultxdg = malloc (strlen ("XDG_CONFIG_HOME=") + strlen (userhome) + 1);
	sprintf (defaultxdg, "XDG_CONFIG_HOME=%s", userhome);
	_putenv (defaultxdg);
	free (defaultxdg);

	assert (sizeof (settings->keys) / sizeof (*settings->keys) ==
			sizeof (dispatchActions) / sizeof (*dispatchActions));

	/* apply defaults */
	settings->audioQuality = PIANO_AQ_HIGH;
	settings->autoselect = true;
	settings->history = 5;
	settings->volume = 0;
	settings->timeout = 30; /* seconds */
	settings->gainMul = 1.0;
	/* should be > 4, otherwise expired audio urls (403) can stop playback */
	settings->maxRetry = 5;
	settings->sortOrder = BAR_SORT_NAME_AZ;
	settings->loveIcon = strdup (" <3");
	settings->banIcon = strdup (" </3");
	settings->tiredIcon = strdup (" zZ");
	settings->atIcon = strdup (" @ ");
	settings->npSongFormat = strdup ("\"%t\" by \"%a\" on \"%l\"%r%@%s");
	settings->npStationFormat = strdup ("Station \"%n\" (%i)");
	settings->listSongFormat = strdup ("%i) %a - %t%r");
	settings->titleFormat = strdup (TITLE " - \"%t\" by \"%a\" on \"%l\"%r%@%s");
	settings->player = NULL;
	settings->rpcHost = strdup (PIANO_RPC_HOST);
	settings->rpcTlsPort = strdup ("443");
	settings->partnerUser = strdup ("android");
	settings->partnerPassword = strdup ("AC7IBG09A3DTSYM4R41UJWL07VLN8JI7");
	settings->device = strdup ("android-generic");
	settings->inkey = strdup ("R=U!LH$O2B#");
	settings->outkey = strdup ("6#26FRL$ZWD");
	settings->fifo = BarGetXdgConfigDir (PACKAGE_PIPE);
	assert (settings->fifo != NULL);

	settings->msgFormat[MSG_NONE].prefix = NULL;
	settings->msgFormat[MSG_NONE].postfix = NULL;
	settings->msgFormat[MSG_INFO].prefix = strdup ("(i) ");
	settings->msgFormat[MSG_INFO].postfix = NULL;
	settings->msgFormat[MSG_PLAYING].prefix = strdup ("|>  ");
	settings->msgFormat[MSG_PLAYING].postfix = NULL;
	settings->msgFormat[MSG_TIME].prefix = strdup ("#   ");
	settings->msgFormat[MSG_TIME].postfix = NULL;
	settings->msgFormat[MSG_ERR].prefix = strdup ("/!\\ ");
	settings->msgFormat[MSG_ERR].postfix = NULL;
	settings->msgFormat[MSG_QUESTION].prefix = strdup ("[?] ");
	settings->msgFormat[MSG_QUESTION].postfix = NULL;
	settings->msgFormat[MSG_LIST].prefix = strdup ("\t");
	settings->msgFormat[MSG_LIST].postfix = NULL;
	settings->msgFormat[MSG_DEBUG].prefix = NULL;
	settings->msgFormat[MSG_DEBUG].postfix = NULL;

	for (size_t i = 0; i < BAR_KS_COUNT; i++) {
		settings->keys[i] = dispatchActions[i].defaultKey;
	}

	/* read config files */
	for (size_t j = 0; j < sizeof (configfiles) / sizeof (*configfiles); j++) {
		static const char *formatMsgPrefix = "format_msg_";
		FILE *configfd;
		char line[512];
		size_t lineNum = 0;

		char * const path = BarGetXdgConfigDir (configfiles[j]);
		assert (path != NULL);
		if ((configfd = fopen (path, "r")) == NULL) {
			free (path);
			continue;
		}

		while (1) {
			++lineNum;
			char * const ret = fgets (line, sizeof (line), configfd);
			if (ret == NULL) {
				/* EOF or error */
				break;
			}
			if (strchr (line, '\n') == NULL && !feof (configfd)) {
				BarUiMsg (settings, MSG_INFO, "Line %s:%zu too long, "
						"ignoring\n", path, lineNum);
				continue;
			}
			/* parse lines that match "^\s*(.*?)\s?=\s?(.*)$". Windows and Unix
			 * line terminators are supported. */
			char *key = line;

			/* skip leading spaces */
			while (isspace ((unsigned char) key[0])) {
				++key;
			}

			/* skip comments */
			if (key[0] == '#') {
				continue;
			}

			/* search for delimiter and split key-value pair */
			char *val = strchr (line, '=');
			if (val == NULL) {
				/* no warning for empty lines */
				if (key[0] != '\0') {
					BarUiMsg (settings, MSG_INFO,
							"Invalid line at %s:%zu\n", path, lineNum);
				}
				/* invalid line */
				continue;
			}
			*val = '\0';
			++val;

			/* drop spaces at the end */
			char *keyend = &key[strlen (key)-1];
			while (keyend >= key && isspace ((unsigned char) *keyend)) {
				*keyend = '\0';
				--keyend;
			}

			/* strip at most one space, legacy cruft, required for values with
			 * leading spaces like love_icon */
			if (isspace ((unsigned char) val[0])) {
				++val;
			}
			/* drop trailing cr/lf */
			char *valend = &val[strlen (val)-1];
			while (valend >= val && (*valend == '\r' || *valend == '\n')) {
				*valend = '\0';
				--valend;
			}

			if (streq ("control_proxy", key)) {
				settings->controlProxy = strdup (val);
			} else if (streq ("proxy", key)) {
				settings->proxy = strdup (val);
			} else if (streq ("bind_to", key)) {
				settings->bindTo = strdup (val);
			} else if (streq ("user", key)) {
				settings->username = strdup (val);
			} else if (streq ("password", key)) {
				settings->password = strdup (val);
			} else if (streq ("password_command", key)) {
				settings->passwordCmd = strdup (val);
			} else if (streq ("rpc_host", key)) {
				free (settings->rpcHost);
				settings->rpcHost = strdup (val);
			} else if (streq ("rpc_tls_port", key)) {
				free (settings->rpcTlsPort);
				settings->rpcTlsPort = strdup (val);
			} else if (streq ("partner_user", key)) {
				free (settings->partnerUser);
				settings->partnerUser = strdup (val);
			} else if (streq ("partner_password", key)) {
				free (settings->partnerPassword);
				settings->partnerPassword = strdup (val);
			} else if (streq ("device", key)) {
				free (settings->device);
				settings->device = strdup (val);
			} else if (streq ("encrypt_password", key)) {
				free (settings->outkey);
				settings->outkey = strdup (val);
			} else if (streq ("decrypt_password", key)) {
				free (settings->inkey);
				settings->inkey = strdup (val);
			} else if (streq ("ca_bundle", key)) {
				free (settings->caBundle);
				settings->caBundle = strdup (val);
			} else if (memcmp ("act_", key, 4) == 0) {
				size_t i;
				/* keyboard shortcuts */
				for (i = 0; i < BAR_KS_COUNT; i++) {
					if (streq (dispatchActions[i].configKey, key)) {
						if (streq (val, "disabled")) {
							settings->keys[i] = BAR_KS_DISABLED;
						} else {
							settings->keys[i] = val[0];
						}
						break;
					}
				}
			} else if (streq ("audio_quality", key)) {
				if (streq (val, "low")) {
					settings->audioQuality = PIANO_AQ_LOW;
				} else if (streq (val, "medium")) {
					settings->audioQuality = PIANO_AQ_MEDIUM;
				} else if (streq (val, "high")) {
					settings->audioQuality = PIANO_AQ_HIGH;
				}
			} else if (streq ("autostart_station", key)) {
				free (settings->autostartStation);
				settings->autostartStation = strdup (val);
			} else if (streq ("event_command", key)) {
				settings->eventCmd = BarSettingsExpandTilde (val, userhome);
			} else if (streq ("history", key)) {
				settings->history = atoi (val);
			} else if (streq ("max_retry", key)) {
				settings->maxRetry = atoi (val);
			} else if (streq ("timeout", key)) {
				settings->timeout = atoi (val);
			} else if (streq ("sort", key)) {
				size_t i;
				static const char *mapping[] = {"name_az",
						"name_za",
						"quickmix_01_name_az",
						"quickmix_01_name_za",
						"quickmix_10_name_az",
						"quickmix_10_name_za",
						};
				for (i = 0; i < BAR_SORT_COUNT; i++) {
					if (streq (mapping[i], val)) {
						settings->sortOrder = i;
						break;
					}
				}
			} else if (streq ("love_icon", key)) {
				free (settings->loveIcon);
				settings->loveIcon = strdup (val);
			} else if (streq ("ban_icon", key)) {
				free (settings->banIcon);
				settings->banIcon = strdup (val);
			} else if (streq ("tired_icon", key)) {
				free (settings->tiredIcon);
				settings->tiredIcon = strdup (val);
			} else if (streq ("at_icon", key)) {
				free (settings->atIcon);
				settings->atIcon = strdup (val);
			} else if (streq ("volume", key)) {
				settings->volume = atoi (val);
			} else if (streq ("gain_mul", key)) {
				settings->gainMul = (float)atof (val);
			} else if (streq ("format_nowplaying_song", key)) {
				free (settings->npSongFormat);
				settings->npSongFormat = strdup (val);
			} else if (streq ("format_nowplaying_station", key)) {
				free (settings->npStationFormat);
				settings->npStationFormat = strdup (val);
			} else if (streq ("format_list_song", key)) {
				free (settings->listSongFormat);
				settings->listSongFormat = strdup (val);
			} else if (streq ("format_title", key)) {
				free (settings->titleFormat);
				settings->titleFormat = strdup (val);
			} else if (streq ("player", key)) {
				free (settings->player);
				settings->player = strdup (val);
			} else if (streq ("fifo", key)) {
				free (settings->fifo);
				settings->fifo = BarSettingsExpandTilde (val, userhome);
			} else if (streq ("autoselect", key)) {
				settings->autoselect = atoi (val);
			} else if (strncmp (formatMsgPrefix, key,
					strlen (formatMsgPrefix)) == 0) {
				static const char *mapping[] = {"none", "info", "nowplaying",
						"time", "err", "question", "list", "debug"};
				const char *typeStart = key + strlen (formatMsgPrefix);
				for (size_t i = 0; i < sizeof (mapping) / sizeof (*mapping); i++) {
					if (streq (typeStart, mapping[i])) {
						const char *formatPos = strstr (val, "%s");
						
						/* keep default if there is no format character */
						if (formatPos != NULL) {
							BarMsgFormatStr_t *format = &settings->msgFormat[i];

							free (format->prefix);
							free (format->postfix);

							const size_t prefixLen = formatPos - val;
							format->prefix = calloc (prefixLen + 1,
									sizeof (*format->prefix));
							memcpy (format->prefix, val, prefixLen);

							const size_t postfixLen = strlen (val) -
									(formatPos-val) - 2;
							format->postfix = calloc (postfixLen + 1,
									sizeof (*format->postfix));
							memcpy (format->postfix, formatPos+2, postfixLen);
						}
						break;
					}
				}
			}
		}

		fclose (configfd);
		free (path);
	}

	/* check environment variable if proxy is not set explicitly */
	if (settings->proxy == NULL) {
		char *tmpProxy = getenv ("http_proxy");
		if (tmpProxy != NULL && strlen (tmpProxy) > 0) {
			settings->proxy = strdup (tmpProxy);
		}
	}

	free (userhome);
}
Esempio n. 7
0
/*	read app settings from file; format is: key = value\n
 *	@param where to save these settings
 *	@return nothing yet
 */
void BarSettingsRead (BarSettings_t *settings) {
	char configfile[PATH_MAX], key[256], val[256];
	FILE *configfd;

	assert (sizeof (settings->keys) / sizeof (*settings->keys) ==
			sizeof (dispatchActions) / sizeof (*dispatchActions));

	/* apply defaults */
	#ifdef ENABLE_FAAD
	settings->audioFormat = PIANO_AF_AACPLUS;
	#else
		#ifdef ENABLE_MAD
		settings->audioFormat = PIANO_AF_MP3;
		#endif
	#endif
	settings->history = 5;
	settings->volume = 0;
	settings->sortOrder = BAR_SORT_NAME_AZ;
	settings->loveIcon = strdup ("<3");
	settings->banIcon = strdup ("</3");
	for (size_t i = 0; i < BAR_KS_COUNT; i++) {
		settings->keys[i] = dispatchActions[i].defaultKey;
	}

	BarGetXdgConfigDir (PACKAGE "/config", configfile, sizeof (configfile));
	if ((configfd = fopen (configfile, "r")) == NULL) {
		return;
	}

	/* read config file */
	while (1) {
		int scanRet = fscanf (configfd, "%255s = %255[^\n]", key, val);
		if (scanRet == EOF) {
			break;
		} else if (scanRet != 2) {
			/* invalid config line */
			continue;
		}
		if (streq ("control_proxy", key)) {
			settings->controlProxy = strdup (val);
		} else if (streq ("proxy", key)) {
			settings->proxy = strdup (val);
		} else if (streq ("user", key)) {
			settings->username = strdup (val);
		} else if (streq ("password", key)) {
			settings->password = strdup (val);
		} else if (memcmp ("act_", key, 4) == 0) {
			size_t i;
			/* keyboard shortcuts */
			for (i = 0; i < BAR_KS_COUNT; i++) {
				if (streq (dispatchActions[i].configKey, key)) {
					if (streq (val, "disabled")) {
						settings->keys[i] = BAR_KS_DISABLED;
					} else {
						settings->keys[i] = val[0];
					}
					break;
				}
			}
		} else if (streq ("audio_format", key)) {
			if (streq (val, "aacplus")) {
				settings->audioFormat = PIANO_AF_AACPLUS;
			} else if (streq (val, "mp3")) {
				settings->audioFormat = PIANO_AF_MP3;
			} else if (streq (val, "mp3-hifi")) {
				settings->audioFormat = PIANO_AF_MP3_HI;
			}
		} else if (streq ("autostart_station", key)) {
			settings->autostartStation = strdup (val);
		} else if (streq ("event_command", key)) {
			settings->eventCmd = strdup (val);
		} else if (streq ("history", key)) {
			settings->history = atoi (val);
		} else if (streq ("sort", key)) {
			size_t i;
			static const char *mapping[] = {"name_az",
					"name_za",
					"quickmix_01_name_az",
					"quickmix_01_name_za",
					"quickmix_10_name_az",
					"quickmix_10_name_za",
					};
			for (i = 0; i < BAR_SORT_COUNT; i++) {
				if (streq (mapping[i], val)) {
					settings->sortOrder = i;
					break;
				}
			}
		} else if (streq ("love_icon", key)) {
			free (settings->loveIcon);
			settings->loveIcon = strdup (val);
		} else if (streq ("ban_icon", key)) {
			free (settings->banIcon);
			settings->banIcon = strdup (val);
		} else if (streq ("volume", key)) {
			settings->volume = atoi (val);
		}
	}

	/* check environment variable if proxy is not set explicitly */
	if (settings->proxy == NULL) {
		char *tmpProxy = getenv ("http_proxy");
		if (tmpProxy != NULL && strlen (tmpProxy) > 0) {
			settings->proxy = strdup (tmpProxy);
		}
	}

	fclose (configfd);
}
Esempio n. 8
0
int main (int argc, char **argv) {
	static BarApp_t app;
	char ctlPath[PATH_MAX];
	/* terminal attributes _before_ we started messing around with ~ECHO */
	struct termios termOrig;

	memset (&app, 0, sizeof (app));

	/* save terminal attributes, before disabling echoing */
	BarTermSave (&termOrig);
	BarTermSetEcho (0);
	BarTermSetBuffer (0);

	/* init some things */
	ao_initialize ();
	PianoInit (&app.ph);

	WaitressInit (&app.waith);
	app.waith.url.host = strdup (PIANO_RPC_HOST);
	app.waith.url.port = strdup (PIANO_RPC_PORT);

	BarSettingsInit (&app.settings);
	BarSettingsRead (&app.settings);

	BarUiMsg (&app.settings, MSG_NONE,
			"Welcome to " PACKAGE " (" VERSION ")! ");
	if (app.settings.keys[BAR_KS_HELP] == BAR_KS_DISABLED) {
		BarUiMsg (&app.settings, MSG_NONE, "\n");
	} else {
		BarUiMsg (&app.settings, MSG_NONE,
				"Press %c for a list of commands.\n",
				app.settings.keys[BAR_KS_HELP]);
	}

	/* init fds */
	FD_ZERO(&app.input.set);
	app.input.fds[0] = STDIN_FILENO;
	FD_SET(app.input.fds[0], &app.input.set);

	BarGetXdgConfigDir (PACKAGE "/ctl", ctlPath, sizeof (ctlPath));
	/* open fifo read/write so it won't EOF if nobody writes to it */
	assert (sizeof (app.input.fds) / sizeof (*app.input.fds) >= 2);
	app.input.fds[1] = open (ctlPath, O_RDWR);
	if (app.input.fds[1] != -1) {
		FD_SET(app.input.fds[1], &app.input.set);
		BarUiMsg (&app.settings, MSG_INFO, "Control fifo at %s opened\n",
				ctlPath);
	}
	app.input.maxfd = app.input.fds[0] > app.input.fds[1] ? app.input.fds[0] :
			app.input.fds[1];
	++app.input.maxfd;

	BarMainLoop (&app);

	if (app.input.fds[1] != -1) {
		close (app.input.fds[1]);
	}

	PianoDestroy (&app.ph);
	PianoDestroyPlaylist (app.songHistory);
	PianoDestroyPlaylist (app.playlist);
	ao_shutdown();
	BarSettingsDestroy (&app.settings);

	/* restore terminal attributes, zsh doesn't need this, bash does... */
	BarTermRestore (&termOrig);

	return 0;
}
Esempio n. 9
0
/*	read app settings from file; format is: key = value\n
 *	@param where to save these settings
 *	@return nothing yet
 */
void BarSettingsRead (BarSettings_t *settings) {
	char configfile[PATH_MAX], key[256], val[256];
	FILE *configfd = NULL;
	static const char *formatMsgPrefix = "format_msg_";

	assert (sizeof (settings->keys) / sizeof (*settings->keys) ==
			sizeof (dispatchActions) / sizeof (*dispatchActions));

	/* apply defaults */
	#ifdef ENABLE_FAAD
	settings->audioFormat = PIANO_AF_AACPLUS;
	#else
		#ifdef ENABLE_MAD
		settings->audioFormat = PIANO_AF_MP3;
		#endif
	#endif
	settings->history = 5;
	settings->volume = 0;
	settings->sortOrder = BAR_SORT_NAME_AZ;
	settings->loveIcon = strdup (" <3");
	settings->banIcon = strdup (" </3");
	settings->atIcon = strdup (" @ ");
	settings->npSongFormat = strdup ("\"%t\" by \"%a\" on \"%l\"%r%@%s");
	settings->npStationFormat = strdup ("Station \"%n\" (%i)");

	settings->msgFormat[MSG_NONE].prefix = NULL;
	settings->msgFormat[MSG_NONE].postfix = NULL;
	settings->msgFormat[MSG_INFO].prefix = strdup ("(i) ");
	settings->msgFormat[MSG_INFO].postfix = NULL;
	settings->msgFormat[MSG_PLAYING].prefix = strdup ("|>  ");
	settings->msgFormat[MSG_PLAYING].postfix = NULL;
	settings->msgFormat[MSG_TIME].prefix = strdup ("#   ");
	settings->msgFormat[MSG_TIME].postfix = NULL;
	settings->msgFormat[MSG_ERR].prefix = strdup ("/!\\ ");
	settings->msgFormat[MSG_ERR].postfix = NULL;
	settings->msgFormat[MSG_QUESTION].prefix = strdup ("[?] ");
	settings->msgFormat[MSG_QUESTION].postfix = NULL;
	settings->msgFormat[MSG_LIST].prefix = strdup ("\t");
	settings->msgFormat[MSG_LIST].postfix = NULL;

	settings->useSpaces = false;
	settings->embedCover = true;

	for (size_t i = 0; i < BAR_KS_COUNT; i++) {
		settings->keys[i] = dispatchActions[i].defaultKey;
	}

	BarGetXdgConfigDir (PACKAGE "/config", configfile, sizeof (configfile));

	/* read config file */
	if ((configfd = fopen (configfile, "r")) != NULL) {
		while (1) {
			int scanRet = fscanf (configfd, "%255s = %255[^\n]", key, val);
			if (scanRet == EOF) {
				break;
			} else if (scanRet != 2) {
				/* invalid config line */
				continue;
			}
			if (streq ("control_proxy", key)) {
				free (settings->controlProxy);
				settings->controlProxy = strdup (val);
			} else if (streq ("proxy", key)) {
				free (settings->proxy);
				settings->proxy = strdup (val);
			} else if (streq ("user", key)) {
				free (settings->username);
				settings->username = strdup (val);
			} else if (streq ("password", key)) {
				free (settings->password);
				settings->password = strdup (val);
			} else if (memcmp ("act_", key, 4) == 0) {
				size_t i;
				/* keyboard shortcuts */
				for (i = 0; i < BAR_KS_COUNT; i++) {
					if (streq (dispatchActions[i].configKey, key)) {
						if (streq (val, "disabled")) {
							settings->keys[i] = BAR_KS_DISABLED;
						} else {
							settings->keys[i] = val[0];
						}
						break;
					}
				}
			} else if (streq ("audio_format", key)) {
				if (streq (val, "aacplus")) {
					settings->audioFormat = PIANO_AF_AACPLUS;
				} else if (streq (val, "mp3")) {
					settings->audioFormat = PIANO_AF_MP3;
				} else if (streq (val, "mp3-hifi")) {
					settings->audioFormat = PIANO_AF_MP3_HI;
				}
			} else if (streq ("audio_file_dir", key)) {
				free (settings->audioFileDir);
				settings->audioFileDir = strdup(val);
			} else if (streq ("audio_file_name", key)) {
				free (settings->audioFileName);
				settings->audioFileName = strdup(val);
			} else if (streq ("use_spaces", key)) {
				if (streq ("true", val)) {
					settings->useSpaces = true;
				}
			} else if (streq ("embed_cover", key)) {
				if (!streq ("true", val)) {
					settings->embedCover = false;
				}
			} else if (streq ("autostart_station", key)) {
				free (settings->autostartStation);
				settings->autostartStation = strdup (val);
			} else if (streq ("event_command", key)) {
				free (settings->eventCmd);
				settings->eventCmd = strdup (val);
			} else if (streq ("history", key)) {
				settings->history = atoi (val);
			} else if (streq ("sort", key)) {
				size_t i;
				static const char *mapping[] = {"name_az",
						"name_za",
						"quickmix_01_name_az",
						"quickmix_01_name_za",
						"quickmix_10_name_az",
						"quickmix_10_name_za",
						};
				for (i = 0; i < BAR_SORT_COUNT; i++) {
					if (streq (mapping[i], val)) {
						settings->sortOrder = i;
						break;
					}
				}
			} else if (streq ("love_icon", key)) {
				free (settings->loveIcon);
				settings->loveIcon = strdup (val);
			} else if (streq ("ban_icon", key)) {
				free (settings->banIcon);
				settings->banIcon = strdup (val);
			} else if (streq ("at_icon", key)) {
			free (settings->atIcon);
			settings->atIcon = strdup (val);
			} else if (streq ("volume", key)) {
				settings->volume = atoi (val);
			} else if (streq ("format_nowplaying_song", key)) {
				free (settings->npSongFormat);
				settings->npSongFormat = strdup (val);
			} else if (streq ("format_nowplaying_station", key)) {
				free (settings->npStationFormat);
				settings->npStationFormat = strdup (val);
			} else if (strncmp (formatMsgPrefix, key,
					strlen (formatMsgPrefix)) == 0) {
				static const char *mapping[] = {"none", "info", "nowplaying",
						"time", "err", "question", "list"};
				const char *typeStart = key + strlen (formatMsgPrefix);
				for (size_t i = 0; i < sizeof (mapping) / sizeof (*mapping); i++) {
					if (streq (typeStart, mapping[i])) {
						const char *formatPos = strstr (val, "%s");
					
						/* keep default if there is no format character */
						if (formatPos != NULL) {
							BarMsgFormatStr_t *format = &settings->msgFormat[i];

							free (format->prefix);
							free (format->postfix);

							const size_t prefixLen = formatPos - val;
							format->prefix = calloc (prefixLen + 1,
									sizeof (*format->prefix));
							memcpy (format->prefix, val, prefixLen);

							const size_t postfixLen = strlen (val) -
									(formatPos-val) - 2;
							format->postfix = calloc (postfixLen + 1,
									sizeof (*format->postfix));
							memcpy (format->postfix, formatPos+2, postfixLen);
						}
						break;
					}
				}
			}
		}
	}

	/* check environment variable if proxy is not set explicitly */
	if (settings->proxy == NULL) {
		char *tmpProxy = getenv ("http_proxy");
		if (tmpProxy != NULL && strlen (tmpProxy) > 0) {
			settings->proxy = strdup (tmpProxy);
		}
	}

	/* Use a local ./mp3 directory if no audio file directory was set. */
	if (settings->audioFileDir == NULL) {
		settings->audioFileDir = strdup(BAR_DEFAULT_AUDIO_FILE_DIR);
	}

	/* Use the default file name if none was set. */
	if (settings->audioFileName == NULL) {
		settings->audioFileName = strdup(BAR_DEFAULT_AUDIO_FILE_NAME);
	}

	if (configfd != NULL) {
		fclose (configfd);
	}

	return;
}
Esempio n. 10
0
int main (int argc, char **argv) {
	/* handles */
	PianoHandle_t ph;
	static struct audioPlayer player;
	BarSettings_t settings;
	pthread_t playerThread;
	/* playlist; first item is current song */
	PianoSong_t *playlist = NULL;
	PianoSong_t *songHistory = NULL;
	PianoStation_t *curStation = NULL;
	char doQuit = 0;
	/* FIXME: max path length? */
	char ctlPath[1024];
	FILE *ctlFd = NULL;
	struct timeval selectTimeout;
	int maxFd, selectFds[2];
	fd_set readSet, readSetCopy;
	char buf = '\0';
	/* terminal attributes _before_ we started messing around with ~ECHO */
	struct termios termOrig;

	BarUiMsg (MSG_NONE, "Welcome to " PACKAGE "!\n");

	/* save terminal attributes, before disabling echoing */
	BarTermSave (&termOrig);

	BarTermSetEcho (0);
	BarTermSetBuffer (0);
	/* init some things */
	ao_initialize ();
	PianoInit (&ph);
	BarSettingsInit (&settings);
	BarSettingsRead (&settings);

	/* init fds */
	FD_ZERO(&readSet);
	selectFds[0] = fileno (stdin);
	FD_SET(selectFds[0], &readSet);
	maxFd = selectFds[0] + 1;

	BarGetXdgConfigDir (PACKAGE "/ctl", ctlPath, sizeof (ctlPath));
	/* FIXME: why is r_+_ required? */
	ctlFd = fopen (ctlPath, "r+");
	if (ctlFd != NULL) {
		selectFds[1] = fileno (ctlFd);
		FD_SET(selectFds[1], &readSet);
		/* assuming ctlFd is always > stdin */
		maxFd = selectFds[1] + 1;
		BarUiMsg (MSG_INFO, "Control fifo at %s opened\n", ctlPath);
	}

	if (settings.username == NULL) {
		char nameBuf[100];
		BarUiMsg (MSG_QUESTION, "Username: "******"Password: "******"Login... ");
	if (BarUiPrintPianoStatus (PianoConnect (&ph, settings.username,
			settings.password)) !=
			PIANO_RET_OK) {
		BarTermRestore (&termOrig);
		return 0;
	}
	BarUiMsg (MSG_INFO, "Get stations... ");
	if (BarUiPrintPianoStatus (PianoGetStations (&ph)) != PIANO_RET_OK) {
		BarTermRestore (&termOrig);
		return 0;
	}

	/* try to get autostart station */
	if (settings.autostartStation != NULL) {
		curStation = PianoFindStationById (ph.stations,
				settings.autostartStation);
		if (curStation == NULL) {
			BarUiMsg (MSG_ERR, "Error: Autostart station not found.\n");
		}
	}
	/* no autostart? ask the user */
	if (curStation == NULL) {
		curStation = BarUiSelectStation (&ph, "Select station: ", stdin);
	}
	if (curStation != NULL) {
		BarUiPrintStation (curStation);
	}

	/* little hack, needed to signal: hey! we need a playlist, but don't
	 * free anything (there is nothing to be freed yet) */
	memset (&player, 0, sizeof (player));

	while (!doQuit) {
		/* song finished playing, clean up things/scrobble song */
		if (player.mode == PLAYER_FINISHED_PLAYBACK) {
			BarUiStartEventCmd (&settings, "songfinish", curStation, playlist,
					&player, PIANO_RET_OK);
			/* FIXME: pthread_join blocks everything if network connection
			 * is hung up e.g. */
			void *threadRet;
			pthread_join (playerThread, &threadRet);
			/* don't continue playback if thread reports error */
			if (threadRet != NULL) {
				curStation = NULL;
			}
			memset (&player, 0, sizeof (player));
		}

		/* check whether player finished playing and start playing new
		 * song */
		if (player.mode >= PLAYER_FINISHED_PLAYBACK ||
				player.mode == PLAYER_FREED) {
			if (curStation != NULL) {
				/* what's next? */
				if (playlist != NULL) {
					if (settings.history != 0) {
						/* prepend song to history list */
						PianoSong_t *tmpSong = songHistory;
						songHistory = playlist;
						/* select next song */
						playlist = playlist->next;
						songHistory->next = tmpSong;

						/* limit history's length */
						/* start with 1, so we're stopping at n-1 and have the
						 * chance to set ->next = NULL */
						unsigned int i = 1;
						tmpSong = songHistory;
						while (i < settings.history && tmpSong != NULL) {
							tmpSong = tmpSong->next;
							++i;
						}
						/* if too many songs in history... */
						if (tmpSong != NULL) {
							PianoSong_t *delSong = tmpSong->next;
							tmpSong->next = NULL;
							if (delSong != NULL) {
								PianoDestroyPlaylist (delSong);
							}
						}
					} else {
						/* don't keep history */
						playlist = playlist->next;
					}
				}
				if (playlist == NULL) {
					PianoReturn_t pRet = PIANO_RET_ERR;

					BarUiMsg (MSG_INFO, "Receiving new playlist... ");
					if ((pRet = BarUiPrintPianoStatus (PianoGetPlaylist (&ph,
							curStation->id, settings.audioFormat,
							&playlist))) != PIANO_RET_OK) {
						curStation = NULL;
					} else {
						if (playlist == NULL) {
							BarUiMsg (MSG_INFO, "No tracks left.\n");
							curStation = NULL;
						}
					}
					BarUiStartEventCmd (&settings, "stationfetchplaylist",
							curStation, playlist, &player, pRet);
				}
				/* song ready to play */
				if (playlist != NULL) {
					BarUiPrintSong (playlist, curStation->isQuickMix ?
							PianoFindStationById (ph.stations,
							playlist->stationId) : NULL);

					if (playlist->audioUrl == NULL) {
						BarUiMsg (MSG_ERR, "Invalid song url.\n");
					} else {
						/* setup player */
						memset (&player, 0, sizeof (player));

						WaitressInit (&player.waith);
						WaitressSetUrl (&player.waith, playlist->audioUrl);

						player.gain = playlist->fileGain;
						player.audioFormat = playlist->audioFormat;

						/* Setup dump directories. */
						prepare_dump_name(player.dump_filename, playlist);

						/* Setup dump handle. If we can read the file,
						 * then it already exists so don't re-write. */
						if (access(player.dump_filename, R_OK) != 0) {
							player.dump_handle = fopen(player.dump_filename, "w");
							BarUiMsg(MSG_INFO, "Will dump song...\n");
						} else {
							player.dump_handle = NULL;
							BarUiMsg(MSG_INFO, "Dump file found, will not dump!\n");
						}
			
						/* throw event */
						BarUiStartEventCmd (&settings, "songstart", curStation,
								playlist, &player, PIANO_RET_OK);

						/* start player */
						pthread_create (&playerThread, NULL, BarPlayerThread,
								&player);
					} /* end if audioUrl == NULL */
				} /* end if playlist != NULL */
			} /* end if curStation != NULL */
		}

		/* select modifies its arguments => copy the set */
		memcpy (&readSetCopy, &readSet, sizeof (readSet));
		selectTimeout.tv_sec = 1;
		selectTimeout.tv_usec = 0;

		/* in the meantime: wait for user actions */
		if (select (maxFd, &readSetCopy, NULL, NULL, &selectTimeout) > 0) {
			FILE *curFd = NULL;

			if (FD_ISSET(selectFds[0], &readSetCopy)) {
				curFd = stdin;
			} else if (FD_ISSET(selectFds[1], &readSetCopy)) {
				curFd = ctlFd;
			}
			buf = fgetc (curFd);

			size_t i;
			for (i = 0; i < BAR_KS_COUNT; i++) {
				if (settings.keys[i] == buf) {
					BarKeyShortcutFunc_t idToF[] = {BarUiActHelp,
							BarUiActLoveSong, BarUiActBanSong,
							BarUiActAddMusic, BarUiActCreateStation,
							BarUiActDeleteStation, BarUiActExplain,
							BarUiActStationFromGenre, BarUiActHistory,
							BarUiActSongInfo, BarUiActAddSharedStation,
							BarUiActMoveSong, BarUiActSkipSong, BarUiActPause,
							BarUiActQuit, BarUiActRenameStation,
							BarUiActSelectStation, BarUiActTempBanSong,
							BarUiActPrintUpcoming, BarUiActSelectQuickMix,
							BarUiActDebug, BarUiActBookmark};
					idToF[i] (&ph, &player, &settings, &playlist,
							&curStation, &songHistory, &doQuit, curFd);
					break;
				}
			}
		}

		/* show time */
		if (player.mode >= PLAYER_SAMPLESIZE_INITIALIZED &&
				player.mode < PLAYER_FINISHED_PLAYBACK) {
			/* Ugly: songDuration is unsigned _long_ int! Lets hope this won't
			 * overflow */
			int songRemaining = (signed long int) (player.songDuration - player.songPlayed)
					/ BAR_PLAYER_MS_TO_S_FACTOR;
			char pos = 0;
			if (songRemaining < 0) {
				/* Use plus sign if song is longer than expected */
				pos = 1;
				songRemaining = -songRemaining;
			}
			BarUiMsg (MSG_TIME, "%c%02i:%02i/%02i:%02i\r", (pos ? '+' : '-'),
					songRemaining / 60, songRemaining % 60,
					player.songDuration / BAR_PLAYER_MS_TO_S_FACTOR / 60,
					player.songDuration / BAR_PLAYER_MS_TO_S_FACTOR % 60);
		}
	}

	/* destroy everything (including the world...) */
	if (player.mode != PLAYER_FREED) {
		pthread_join (playerThread, NULL);
	}
	if (ctlFd != NULL) {
		fclose (ctlFd);
	}
	PianoDestroy (&ph);
	PianoDestroyPlaylist (songHistory);
	PianoDestroyPlaylist (playlist);
	ao_shutdown();
	BarSettingsDestroy (&settings);

	/* restore terminal attributes, zsh doesn't need this, bash does... */
	BarTermRestore (&termOrig);

	return 0;
}
Esempio n. 11
0
/*	read app settings from file; format is: key = value\n
 *	@param where to save these settings
 *	@return nothing yet
 */
void BarSettingsRead (BarSettings_t *settings) {
	char * const configfiles[] = { PACKAGE_STATE, PACKAGE_CONFIG };
	char * const userhome = BarSettingsGetHome ();
	assert (userhome != NULL);
	/* set xdg config path (if not set) */
	char * const defaultxdg = malloc (strlen ("XDG_CONFIG_HOME=") + strlen (userhome) + 1);
	sprintf (defaultxdg, "XDG_CONFIG_HOME=%s", userhome);
	_putenv (defaultxdg);
	free (defaultxdg);

	assert (sizeof (settings->keys) / sizeof (*settings->keys) ==
			sizeof (dispatchActions) / sizeof (*dispatchActions));

	/* apply defaults */
	settings->audioQuality = PIANO_AQ_HIGH;
	settings->autoselect = true;
	settings->history = 5;
	settings->volume = 0;
	settings->maxPlayerErrors = 5;
	settings->sortOrder = BAR_SORT_NAME_AZ;
	settings->loveIcon = strdup (" <3");
	settings->banIcon = strdup (" </3");
	settings->atIcon = strdup (" @ ");
	settings->npSongFormat = strdup ("\"%t\" by \"%a\" on \"%l\"%r%@%s");
	settings->npStationFormat = strdup ("Station \"%n\" (%i)");
	settings->listSongFormat = strdup ("%i) %a - %t%r");
	settings->titleFormat = strdup (TITLE " - \"%t\" by \"%a\" on \"%l\"%r%@%s");
	settings->player = NULL;
	settings->rpcHost = strdup (PIANO_RPC_HOST);
	settings->rpcTlsPort = NULL;
	settings->partnerUser = strdup ("android");
	settings->partnerPassword = strdup ("AC7IBG09A3DTSYM4R41UJWL07VLN8JI7");
	settings->device = strdup ("android-generic");
	settings->inkey = strdup ("R=U!LH$O2B#");
	settings->outkey = strdup ("6#26FRL$ZWD");
	settings->fifo = BarGetXdgConfigDir (PACKAGE_PIPE);
	assert (settings->fifo != NULL);

	settings->msgFormat[MSG_NONE].prefix = NULL;
	settings->msgFormat[MSG_NONE].postfix = NULL;
	settings->msgFormat[MSG_INFO].prefix = strdup ("(i) ");
	settings->msgFormat[MSG_INFO].postfix = NULL;
	settings->msgFormat[MSG_PLAYING].prefix = strdup ("|>  ");
	settings->msgFormat[MSG_PLAYING].postfix = NULL;
	settings->msgFormat[MSG_TIME].prefix = strdup ("#   ");
	settings->msgFormat[MSG_TIME].postfix = NULL;
	settings->msgFormat[MSG_ERR].prefix = strdup ("/!\\ ");
	settings->msgFormat[MSG_ERR].postfix = NULL;
	settings->msgFormat[MSG_QUESTION].prefix = strdup ("[?] ");
	settings->msgFormat[MSG_QUESTION].postfix = NULL;
	settings->msgFormat[MSG_LIST].prefix = strdup ("\t");
	settings->msgFormat[MSG_LIST].postfix = NULL;
	settings->msgFormat[MSG_DEBUG].prefix = NULL;
	settings->msgFormat[MSG_DEBUG].postfix = NULL;

	for (size_t i = 0; i < BAR_KS_COUNT; i++) {
		settings->keys[i] = dispatchActions[i].defaultKey;
	}

	/* read config files */
	for (size_t j = 0; j < sizeof (configfiles) / sizeof (*configfiles); j++) {
		static const char *formatMsgPrefix = "format_msg_";
		char key[256], val[256];
		FILE *configfd;

		char * const path = BarGetXdgConfigDir (configfiles[j]);
		assert (path != NULL);
		if ((configfd = fopen (path, "r")) == NULL) {
			free (path);
			continue;
		}

		while (1) {
			char lwhite, rwhite;
			int scanRet = fscanf (configfd, "%255s%c=%c%255[^\n]", key, &lwhite, &rwhite, val);
			if (scanRet == EOF) {
				break;
			} else if (scanRet != 4 || lwhite != ' ' || rwhite != ' ') {
				/* invalid config line */
				continue;
			}
			if (streq ("control_proxy", key)) {
				settings->controlProxy = strdup (val);
			} else if (streq ("proxy", key)) {
				settings->proxy = strdup (val);
			} else if (streq ("user", key)) {
				settings->username = strdup (val);
			} else if (streq ("password", key)) {
				settings->password = strdup (val);
			} else if (streq ("password_command", key)) {
				settings->passwordCmd = strdup (val);
			} else if (streq ("rpc_host", key)) {
				free (settings->rpcHost);
				settings->rpcHost = strdup (val);
			} else if (streq ("rpc_tls_port", key)) {
				free (settings->rpcTlsPort);
				settings->rpcTlsPort = strdup (val);
			} else if (streq ("partner_user", key)) {
				free (settings->partnerUser);
				settings->partnerUser = strdup (val);
			} else if (streq ("partner_password", key)) {
				free (settings->partnerPassword);
				settings->partnerPassword = strdup (val);
			} else if (streq ("device", key)) {
				free (settings->device);
				settings->device = strdup (val);
			} else if (streq ("encrypt_password", key)) {
				free (settings->outkey);
				settings->outkey = strdup (val);
			} else if (streq ("decrypt_password", key)) {
				free (settings->inkey);
				settings->inkey = strdup (val);
			} else if (streq ("ca_bundle", key)) {
				free (settings->caBundle);
				settings->caBundle = strdup (val);
			} else if (memcmp ("act_", key, 4) == 0) {
				size_t i;
				/* keyboard shortcuts */
				for (i = 0; i < BAR_KS_COUNT; i++) {
					if (streq (dispatchActions[i].configKey, key)) {
						if (streq (val, "disabled")) {
							settings->keys[i] = BAR_KS_DISABLED;
						} else {
							settings->keys[i] = val[0];
						}
						break;
					}
				}
			} else if (streq ("audio_quality", key)) {
				if (streq (val, "low")) {
					settings->audioQuality = PIANO_AQ_LOW;
				} else if (streq (val, "medium")) {
					settings->audioQuality = PIANO_AQ_MEDIUM;
				} else if (streq (val, "high")) {
					settings->audioQuality = PIANO_AQ_HIGH;
				}
			} else if (streq ("autostart_station", key)) {
				free (settings->autostartStation);
				settings->autostartStation = strdup (val);
			} else if (streq ("event_command", key)) {
				settings->eventCmd = BarSettingsExpandTilde (val, userhome);
			} else if (streq ("history", key)) {
				settings->history = atoi (val);
			} else if (streq ("max_player_errors", key)) {
				settings->maxPlayerErrors = atoi (val);
			} else if (streq ("sort", key)) {
				size_t i;
				static const char *mapping[] = {"name_az",
						"name_za",
						"quickmix_01_name_az",
						"quickmix_01_name_za",
						"quickmix_10_name_az",
						"quickmix_10_name_za",
						};
				for (i = 0; i < BAR_SORT_COUNT; i++) {
					if (streq (mapping[i], val)) {
						settings->sortOrder = i;
						break;
					}
				}
			} else if (streq ("love_icon", key)) {
				free (settings->loveIcon);
				settings->loveIcon = strdup (val);
			} else if (streq ("ban_icon", key)) {
				free (settings->banIcon);
				settings->banIcon = strdup (val);
			} else if (streq ("at_icon", key)) {
				free (settings->atIcon);
				settings->atIcon = strdup (val);
			} else if (streq ("volume", key)) {
				settings->volume = atoi (val);
			} else if (streq ("format_nowplaying_song", key)) {
				free (settings->npSongFormat);
				settings->npSongFormat = strdup (val);
			} else if (streq ("format_nowplaying_station", key)) {
				free (settings->npStationFormat);
				settings->npStationFormat = strdup (val);
			} else if (streq ("format_list_song", key)) {
				free (settings->listSongFormat);
				settings->listSongFormat = strdup (val);
			} else if (streq ("format_title", key)) {
				free (settings->titleFormat);
				settings->titleFormat = strdup (val);
			} else if (streq ("player", key)) {
				free (settings->player);
				settings->player = strdup (val);
			} else if (streq ("fifo", key)) {
				free (settings->fifo);
				settings->fifo = BarSettingsExpandTilde (val, userhome);
			} else if (streq ("autoselect", key)) {
				settings->autoselect = atoi (val);
			} else if (strncmp (formatMsgPrefix, key,
					strlen (formatMsgPrefix)) == 0) {
				static const char *mapping[] = {"none", "info", "nowplaying",
						"time", "err", "question", "list", "debug"};
				const char *typeStart = key + strlen (formatMsgPrefix);
				for (size_t i = 0; i < sizeof (mapping) / sizeof (*mapping); i++) {
					if (streq (typeStart, mapping[i])) {
						const char *formatPos = strstr (val, "%s");
						
						/* keep default if there is no format character */
						if (formatPos != NULL) {
							BarMsgFormatStr_t *format = &settings->msgFormat[i];

							free (format->prefix);
							free (format->postfix);

							const size_t prefixLen = formatPos - val;
							format->prefix = calloc (prefixLen + 1,
									sizeof (*format->prefix));
							memcpy (format->prefix, val, prefixLen);

							const size_t postfixLen = strlen (val) -
									(formatPos-val) - 2;
							format->postfix = calloc (postfixLen + 1,
									sizeof (*format->postfix));
							memcpy (format->postfix, formatPos+2, postfixLen);
						}
						break;
					}
				}
			}
		}

		fclose (configfd);
		free (path);
	}

	/* check environment variable if proxy is not set explicitly */
	if (settings->proxy == NULL) {
		char *tmpProxy = getenv ("http_proxy");
		if (tmpProxy != NULL && strlen (tmpProxy) > 0) {
			settings->proxy = strdup (tmpProxy);
		}
	}

	free (userhome);
}
Esempio n. 12
0
/*	read app settings from file; format is: key = value\n
 *	@param where to save these settings
 *	@return nothing yet
 */
void BarSettingsRead (BarSettings_t *settings) {
	/* FIXME: what is the max length of a path? */
	char configfile[1024], key[256], val[256];
	size_t i;
	FILE *configfd;
	/* _must_ have same order as in BarKeyShortcutId_t */
	const char defaultKeys[] = {'?', '+', '-', 'a', 'c', 'd', 'e', 'g',
			'h', 'i', 'j', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'x', '$',
			'b', '.'
			};
	const char *shortcutFileKeys[] = {
			"act_help", "act_songlove", "act_songban", "act_stationaddmusic",
			"act_stationcreate", "act_stationdelete", "act_songexplain",
			"act_stationaddbygenre", "act_history", "act_songinfo",
			"act_addshared", "act_songmove", "act_songnext", "act_songpause",
			"act_quit", "act_stationrename", "act_stationchange",
			"act_songtired", "act_upcoming", "act_stationselectquickmix",
			"act_debug", "act_bookmark", "act_download"
			};

	/* apply defaults */
/*	#ifdef ENABLE_FAAD
	settings->audioFormat = PIANO_AF_AACPLUS;
	#else
		#ifdef ENABLE_MAD
		settings->audioFormat = PIANO_AF_MP3;
		#endif
	#endif*/
    settings->audioFormat = PIANO_AF_AACPLUS;
	settings->history = 5;
	memcpy (settings->keys, defaultKeys, sizeof (defaultKeys));

	BarGetXdgConfigDir (PACKAGE "/config", configfile, sizeof (configfile));
	if ((configfd = fopen (configfile, "r")) == NULL) {
		return;
	}

	/* read config file */
	while (1) {
		int scanRet = fscanf (configfd, "%255s = %255[^\n]", key, val);
		if (scanRet == EOF) {
			break;
		} else if (scanRet != 2) {
			/* invalid config line */
			continue;
		}
		if (strcmp ("control_proxy", key) == 0) {
			settings->controlProxy = strdup (val);
		} else if (strcmp ("proxy", key) == 0) {
			settings->proxy = strdup (val);
		} else if (strcmp ("user", key) == 0) {
			settings->username = strdup (val);
		} else if (strcmp ("password", key) == 0) {
			settings->password = strdup (val);
		} else if (strcmp ("download_dir", key) == 0) {
			settings->downloadDir = strdup (val);
		} else if (memcmp ("act_", key, 4) == 0) {
			/* keyboard shortcuts */
			for (i = 0; i < BAR_KS_COUNT; i++) {
				if (strcmp (shortcutFileKeys[i], key) == 0) {
					settings->keys[i] = val[0];
					break;
				}
			}
		} else if (strcmp ("audio_format", key) == 0) {
			if (strcmp (val, "aacplus") == 0) {
				settings->audioFormat = PIANO_AF_AACPLUS;
			} else if (strcmp (val, "mp3") == 0) {
				settings->audioFormat = PIANO_AF_MP3;
			} else if (strcmp (val, "mp3-hifi") == 0) {
				settings->audioFormat = PIANO_AF_MP3_HI;
			}
		} else if (strcmp ("autostart_station", key) == 0) {
			settings->autostartStation = strdup (val);
		} else if (strcmp ("event_command", key) == 0) {
			settings->eventCmd = strdup (val);
		} else if (strcmp ("history", key) == 0) {
			settings->history = atoi (val);
		}
	}
	
	if (settings->downloadDir == NULL) {
		settings->downloadDir = "/tmp";
	}

	/* check environment variable if proxy is not set explicitly */
	if (settings->proxy == NULL) {
		char *tmpProxy = getenv ("http_proxy");
		if (tmpProxy != NULL && strlen (tmpProxy) > 0) {
			settings->proxy = strdup (tmpProxy);
		}
	}

	fclose (configfd);
}
Esempio n. 13
0
/*	read app settings from file; format is: key = value\n
 *	@param where to save these settings
 *	@return nothing yet
 */
void BarSettingsRead (BarSettings_t *settings) {
	char *configfiles[] = {PACKAGE "/state", PACKAGE "/config"};

	assert (sizeof (settings->keys) / sizeof (*settings->keys) ==
			sizeof (dispatchActions) / sizeof (*dispatchActions));

	/* apply defaults */
	settings->audioQuality = PIANO_AQ_HIGH;
	settings->autoselect = true;
	settings->history = 5;
	settings->volume = 0;
	settings->maxPlayerErrors = 5;
	settings->sortOrder = BAR_SORT_NAME_AZ;
	settings->loveIcon = strdup (" <3");
	settings->banIcon = strdup (" </3");
	settings->atIcon = strdup (" @ ");
	settings->npSongFormat = strdup ("\"%t\" by \"%a\" on \"%l\"%r%@%s");
	settings->npStationFormat = strdup ("Station \"%n\" (%i)");
	settings->listSongFormat = strdup ("%i) %a - %t%r");
	settings->rpcHost = strdup (PIANO_RPC_HOST);
	settings->rpcTlsPort = NULL;
	settings->partnerUser = strdup ("android");
	settings->partnerPassword = strdup ("AC7IBG09A3DTSYM4R41UJWL07VLN8JI7");
	settings->device = strdup ("android-generic");
	settings->inkey = strdup ("R=U!LH$O2B#");
	settings->outkey = strdup ("6#26FRL$ZWD");
	settings->fifo = malloc (PATH_MAX * sizeof (*settings->fifo));
	BarGetXdgConfigDir (PACKAGE "/ctl", settings->fifo, PATH_MAX);
	memcpy (settings->tlsFingerprint, "\x2D\x0A\xFD\xAF\xA1\x6F\x4B\x5C\x0A"
			"\x43\xF3\xCB\x1D\x47\x52\xF9\x53\x55\x07\xC0",
			sizeof (settings->tlsFingerprint));

	settings->msgFormat[MSG_NONE].prefix = NULL;
	settings->msgFormat[MSG_NONE].postfix = NULL;
	settings->msgFormat[MSG_INFO].prefix = strdup ("(i) ");
	settings->msgFormat[MSG_INFO].postfix = NULL;
	settings->msgFormat[MSG_PLAYING].prefix = strdup ("|>  ");
	settings->msgFormat[MSG_PLAYING].postfix = NULL;
	settings->msgFormat[MSG_TIME].prefix = strdup ("#   ");
	settings->msgFormat[MSG_TIME].postfix = NULL;
	settings->msgFormat[MSG_ERR].prefix = strdup ("/!\\ ");
	settings->msgFormat[MSG_ERR].postfix = NULL;
	settings->msgFormat[MSG_QUESTION].prefix = strdup ("[?] ");
	settings->msgFormat[MSG_QUESTION].postfix = NULL;
	settings->msgFormat[MSG_LIST].prefix = strdup ("\t");
	settings->msgFormat[MSG_LIST].postfix = NULL;

    settings->download = 0;
    settings->downloadSafeFilename = false;
    settings->downloadSeparator = strdup("---");
    settings->downloadCleanup = true;

	for (size_t i = 0; i < BAR_KS_COUNT; i++) {
		settings->keys[i] = dispatchActions[i].defaultKey;
	}

	/* read config files */
	for (size_t j = 0; j < sizeof (configfiles) / sizeof (*configfiles); j++) {
		static const char *formatMsgPrefix = "format_msg_";
		char key[256], val[256], path[PATH_MAX];
		FILE *configfd;

		BarGetXdgConfigDir (configfiles[j], path, sizeof (path));
		if ((configfd = fopen (path, "r")) == NULL) {
			continue;
		}

		while (1) {
			char lwhite, rwhite;
			int scanRet = fscanf (configfd, "%255s%c=%c%255[^\n]", key, &lwhite, &rwhite, val);
			if (scanRet == EOF) {
				break;
			} else if (scanRet != 4 || lwhite != ' ' || rwhite != ' ') {
				/* invalid config line */
				continue;
			}
			if (streq ("control_proxy", key)) {
				settings->controlProxy = strdup (val);
			} else if (streq ("proxy", key)) {
				settings->proxy = strdup (val);
			} else if (streq ("user", key)) {
				settings->username = strdup (val);
			} else if (streq ("password", key)) {
				settings->password = strdup (val);
			} else if (streq ("password_command", key)) {
				settings->passwordCmd = strdup (val);
			} else if (streq ("rpc_host", key)) {
				free (settings->rpcHost);
				settings->rpcHost = strdup (val);
			} else if (streq ("rpc_tls_port", key)) {
				free (settings->rpcTlsPort);
				settings->rpcTlsPort = strdup (val);
			} else if (streq ("partner_user", key)) {
				free (settings->partnerUser);
				settings->partnerUser = strdup (val);
			} else if (streq ("partner_password", key)) {
				free (settings->partnerPassword);
				settings->partnerPassword = strdup (val);
			} else if (streq ("device", key)) {
				free (settings->device);
				settings->device = strdup (val);
			} else if (streq ("encrypt_password", key)) {
				free (settings->outkey);
				settings->outkey = strdup (val);
			} else if (streq ("decrypt_password", key)) {
				free (settings->inkey);
				settings->inkey = strdup (val);
			} else if (memcmp ("act_", key, 4) == 0) {
				size_t i;
				/* keyboard shortcuts */
				for (i = 0; i < BAR_KS_COUNT; i++) {
					if (streq (dispatchActions[i].configKey, key)) {
						if (streq (val, "disabled")) {
							settings->keys[i] = BAR_KS_DISABLED;
						} else {
							settings->keys[i] = val[0];
						}
						break;
					}
				}
			} else if (streq ("audio_quality", key)) {
				if (streq (val, "low")) {
					settings->audioQuality = PIANO_AQ_LOW;
				} else if (streq (val, "medium")) {
					settings->audioQuality = PIANO_AQ_MEDIUM;
				} else if (streq (val, "high")) {
					settings->audioQuality = PIANO_AQ_HIGH;
				}
			} else if (streq ("autostart_station", key)) {
				free (settings->autostartStation);
				settings->autostartStation = strdup (val);
			} else if (streq ("event_command", key)) {
				settings->eventCmd = strdup (val);
			} else if (streq ("history", key)) {
				settings->history = atoi (val);
			} else if (streq ("max_player_errors", key)) {
				settings->maxPlayerErrors = atoi (val);
			} else if (streq ("sort", key)) {
				size_t i;
				static const char *mapping[] = {"name_az",
						"name_za",
						"quickmix_01_name_az",
						"quickmix_01_name_za",
						"quickmix_10_name_az",
						"quickmix_10_name_za",
						};
				for (i = 0; i < BAR_SORT_COUNT; i++) {
					if (streq (mapping[i], val)) {
						settings->sortOrder = i;
						break;
					}
				}
			} else if (streq ("love_icon", key)) {
				free (settings->loveIcon);
				settings->loveIcon = strdup (val);
			} else if (streq ("ban_icon", key)) {
				free (settings->banIcon);
				settings->banIcon = strdup (val);
			} else if (streq ("at_icon", key)) {
				free (settings->atIcon);
				settings->atIcon = strdup (val);
			} else if (streq ("volume", key)) {
				settings->volume = atoi (val);
			} else if (streq ("format_nowplaying_song", key)) {
				free (settings->npSongFormat);
				settings->npSongFormat = strdup (val);
			} else if (streq ("format_nowplaying_station", key)) {
				free (settings->npStationFormat);
				settings->npStationFormat = strdup (val);
			} else if (streq ("format_list_song", key)) {
				free (settings->listSongFormat);
				settings->listSongFormat = strdup (val);
			} else if (streq ("fifo", key)) {
				free (settings->fifo);
				settings->fifo = strdup (val);
			} else if (streq ("autoselect", key)) {
				settings->autoselect = atoi (val);
			} else if (streq ("tls_fingerprint", key)) {
				/* expects 40 byte hex-encoded sha1 */
				if (strlen (val) == 40) {
					for (size_t i = 0; i < 20; i++) {
						char hex[3];
						memcpy (hex, &val[i*2], 2);
						hex[2] = '\0';
						settings->tlsFingerprint[i] = strtol (hex, NULL, 16);
					}
				}
			} else if (strncmp (formatMsgPrefix, key,
					strlen (formatMsgPrefix)) == 0) {
				static const char *mapping[] = {"none", "info", "nowplaying",
						"time", "err", "question", "list"};
				const char *typeStart = key + strlen (formatMsgPrefix);
				for (size_t i = 0; i < sizeof (mapping) / sizeof (*mapping); i++) {
					if (streq (typeStart, mapping[i])) {
						const char *formatPos = strstr (val, "%s");
						
						/* keep default if there is no format character */
						if (formatPos != NULL) {
							BarMsgFormatStr_t *format = &settings->msgFormat[i];

							free (format->prefix);
							free (format->postfix);

							const size_t prefixLen = formatPos - val;
							format->prefix = calloc (prefixLen + 1,
									sizeof (*format->prefix));
							memcpy (format->prefix, val, prefixLen);

							const size_t postfixLen = strlen (val) -
									(formatPos-val) - 2;
							format->postfix = calloc (postfixLen + 1,
									sizeof (*format->postfix));
							memcpy (format->postfix, formatPos+2, postfixLen);
						}
						break;
					}
				}
            } else if (streq ("download", key)) {
                settings->download = strdup (val);
            } else if (streq ("download_safe_filename", key)) {
                settings->downloadSafeFilename = ( !streq( val, "0" ) && !streq( val, "false" ) && strlen( val ) ) ? true : false;
            } else if (streq ("download_separator", key)) {
                settings->downloadSeparator = strdup (val);
            } else if (streq ("download_cleanup", key)) {
                settings->downloadCleanup = ( !streq( val, "0" ) && !streq( val, "false" ) && strlen( val ) ) ? true : false;
            }
        }

		fclose (configfd);
	}

	/* check environment variable if proxy is not set explicitly */
	if (settings->proxy == NULL) {
		char *tmpProxy = getenv ("http_proxy");
		if (tmpProxy != NULL && strlen (tmpProxy) > 0) {
			settings->proxy = strdup (tmpProxy);
		}
	}
}