22793b46bd9d6eac3b698f7a6cdbb1f5dadcde8f
[uwplayer.git] / application / settings.c
1 /*
2  * Copyright 2022 Olaf Wintermann
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a 
5  * copy of this software and associated documentation files (the "Software"), 
6  * to deal in the Software without restriction, including without limitation 
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
8  * and/or sell copies of the Software, and to permit persons to whom the 
9  * Software is furnished to do so, subject to the following conditions:
10  * 
11  * The above copyright notice and this permission notice shall be included in 
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
20  * DEALINGS IN THE SOFTWARE.
21  */
22
23 #include "settings.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <pthread.h>
33
34 #include "main.h"
35 #include "utils.h"
36
37 #include <ucx/map.h>
38 #include <ucx/properties.h>
39 #include <ucx/buffer.h>
40 #include <ucx/utils.h>
41
42 #define CONFIG_BASE_DIR ".config"
43 #define UWP_CONFIG_DIR  "uwplayer"
44 #define UWP_CONFIG_FILE "uwplayer.properties"
45
46 static void* player_bin_search_thread(void *data);
47
48 static char *uwp_config_dir;
49 static UcxMap *uwp_settings; 
50
51 static int check_config_dir(void) {
52     char *home = getenv("HOME");
53     if(!home) {
54         return 1;
55     }
56     
57     char *cfg_dir = util_concat_path(home, CONFIG_BASE_DIR);
58     int ret = 0;
59     if(mkdir(cfg_dir, S_IRWXU)) {
60         if(errno != EEXIST) {
61             fprintf(stderr, "Error: Cannot access %s: %s\n", cfg_dir, strerror(errno));
62             ret = 1;
63         }
64     }
65     
66     if(!ret) {
67         uwp_config_dir = util_concat_path(cfg_dir, UWP_CONFIG_DIR);
68         if(mkdir(uwp_config_dir, S_IRWXU)) {
69             if(errno != EEXIST) {
70                 fprintf(stderr, "Error: Cannot access %s: %s\n", uwp_config_dir, strerror(errno));
71                 ret = 1;
72             }
73         }
74     }
75     
76     free(cfg_dir);
77     return ret;
78 }
79
80 int load_settings(void) {
81     if(check_config_dir()) {
82         return 1;
83     }
84     
85     uwp_settings = ucx_map_new(16);
86     
87     char *cfgfile_path = util_concat_path(uwp_config_dir, UWP_CONFIG_FILE);
88     FILE *cfgfile = fopen(cfgfile_path, "r");
89     free(cfgfile_path);
90     
91     int ret = 0;
92     if(cfgfile) {
93         if(ucx_properties_load(uwp_settings, cfgfile)) {
94             fprintf(stderr, "Error: Cannot read uwplayer settings\n");
95             ret = 1;
96         }
97         fclose(cfgfile);
98
99         if(ret) {
100             return ret;
101         }
102     }
103  
104     
105     // check if mpv or mplayer binaries are configured
106     char *player_bin = ucx_map_cstr_get(uwp_settings, UWP_PLAYER_BIN);
107     char *player_type = ucx_map_cstr_get(uwp_settings, UWP_PLAYER_TYPE);
108     
109     if(!player_bin) {
110         // try to find the mpv or mplayer binary path
111         pthread_t st;
112         pthread_create(&st, NULL, player_bin_search_thread, NULL);
113     } else if(!player_type) {
114         fprintf(stderr, "Warning: unknown player type (mplayer, mpv)\n");
115     }
116     
117     return 0;
118 }
119
120 static char* get_which_output(FILE *f, UcxBuffer *buf) {
121     buf->pos = 0;
122     buf->size = 0;
123     ucx_stream_copy(f, buf, (read_func)fread, (write_func)ucx_buffer_write);
124     if(!pclose(f)) {
125         ucx_buffer_putc(buf, 0);
126         size_t i;
127         for(i=0;i<buf->pos;i++) {
128             if(buf->space[i] == '\n') {
129                 buf->space[i] = 0;
130                 break;
131             }
132         }
133         return buf->space;
134     }
135     return NULL;
136 }
137
138 static void finish_bin_search(XtPointer data, XtIntervalId *id) {
139     PlayerInfo *playerInfo = data;
140     ucx_map_cstr_put(uwp_settings, UWP_PLAYER_BIN, playerInfo->bin);
141     ucx_map_cstr_put(uwp_settings, UWP_PLAYER_TYPE, playerInfo->type);
142     free(playerInfo);
143 }
144
145 static void* player_bin_search_thread(void *data) {
146     UcxBuffer *buf = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND);
147     
148     FILE *f = popen("which mpv", "r");
149     if(f) {
150         char *bin = get_which_output(f, buf);
151         if(bin) {
152             PlayerInfo *playerInfo = malloc(sizeof(PlayerInfo));
153             playerInfo->bin = strdup(bin);
154             playerInfo->type = strdup("mpv");
155             AppAddTimeOut(0, finish_bin_search, playerInfo);
156             
157             ucx_buffer_free(buf);
158             return NULL;
159         }
160     }
161     
162     f = popen("which mplayer", "r");
163     if(f) {
164         char *bin = get_which_output(f, buf);
165         if(bin) {
166             PlayerInfo *playerInfo = malloc(sizeof(PlayerInfo));
167             playerInfo->bin = strdup(bin);
168             playerInfo->type = strdup("mplayer");
169             AppAddTimeOut(0, finish_bin_search, playerInfo);
170         }
171     }
172     
173     ucx_buffer_free(buf);
174     return NULL;
175 }