/* 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); }
/* 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); }