1 /*
2  * This file is part of g15daemon.
3  *
4  * g15daemon is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * g15daemon is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with g15daemon; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * (c) 2006-2021 Mike Lampard, Philip Lawatsch, Daniel Menelkir and others
19  *
20  * This daemon listens on localhost port 15550 for client connections,
21  * and arbitrates LCD display.  Allows for multiple simultaneous clients.
22  * Client screens can be cycled through by pressing the 'L1' key.
23  */
24 #ifndef G15DAEMON
25 #define G15DAEMON
26 
27 #ifndef BLACKnWHITE
28 	#define BLACK 1
29 	#define WHITE 0
30 	#define BLACKnWHITE
31 #endif
32 
33 #define LCD_WIDTH 160
34 #define LCD_HEIGHT 43
35 #define LCD_BUFSIZE 1048
36 
37 #ifdef HAVE_CONFIG_H
38 	#include <config.h>
39 #endif
40 
41 #include <pthread.h>
42 #include <pwd.h>
43 #include <syslog.h>
44 
45 #define CLIENT_CMD_GET_KEYSTATE 'k'
46 #define CLIENT_CMD_SWITCH_PRIORITIES 'p'
47 #define CLIENT_CMD_NEVER_SELECT 'n'
48 #define CLIENT_CMD_IS_FOREGROUND 'v'
49 #define CLIENT_CMD_IS_USER_SELECTED 'u'
50 #define CLIENT_CMD_BACKLIGHT 0x80
51 #define CLIENT_CMD_KB_BACKLIGHT 0x8
52 #define CLIENT_CMD_CONTRAST 0x40
53 #define CLIENT_CMD_MKEY_LIGHTS 0x20
54 /* if the following CMD is sent from a client, G15Daemon will not send any MR or G? keypresses via uinput,
55  * all M&G keys must be handled by the client.  If the client dies or exits, normal functions resume. */
56 #define CLIENT_CMD_KEY_HANDLER 0x10
57 
58 enum {
59 	/* plugin types - LCD plugins are provided with a lcd_t and keystates via EVENT when visible.
60 	CORE plugins source and sink events, have no screen associated, and are not able to quit.
61 	by design they implement core functionality..CORE_LIBRARY implements graphic and other
62 	functions for use by other plugins.
63 	*/
64 	G15_PLUGIN_NONE = 0,
65 	G15_PLUGIN_LCD_CLIENT =1,
66 	G15_PLUGIN_CORE_KB_INPUT = 2,
67 	G15_PLUGIN_CORE_OS_KB = 3,
68 	G15_PLUGIN_LCD_SERVER = 4
69 };
70 
71 enum {
72 	/* plugin RETURN values */
73 	G15_PLUGIN_QUIT = -1,
74 	G15_PLUGIN_OK = 0
75 };
76 
77 enum {
78 	/* plugin EVENT types */
79 	G15_EVENT_KEYPRESS = 1,
80 	G15_EVENT_VISIBILITY_CHANGED,
81 	G15_EVENT_USER_FOREGROUND,
82 	G15_EVENT_MLED,
83 	G15_EVENT_BACKLIGHT,
84 	G15_EVENT_CONTRAST,
85 	G15_EVENT_REQ_PRIORITY,
86 	G15_EVENT_CYCLE_PRIORITY,
87 	G15_EVENT_EXITNOW,
88 	/* core event types */
89 	G15_COREVENT_KEYPRESS_IN,
90 	G15_COREVENT_KEYPRESS_OUT
91 };
92 
93 enum {
94 	SCR_HIDDEN = 0,
95 	SCR_VISIBLE
96 };
97 
98 /* plugin global or local */
99 enum {
100 	G15_PLUGIN_NONSHARED = 0,
101 	G15_PLUGIN_SHARED
102 };
103 
104 typedef struct lcd_s lcd_t;
105 typedef struct g15daemon_s g15daemon_t;
106 typedef struct lcdnode_s lcdnode_t;
107 
108 typedef struct plugin_event_s plugin_event_t;
109 typedef struct plugin_info_s plugin_info_t;
110 typedef struct plugin_s plugin_t;
111 
112 typedef struct config_items_s config_items_t;
113 typedef struct config_section_s config_section_t;
114 typedef struct configfile_s configfile_t;
115 
116 typedef struct config_items_s {
117 	config_items_t *next;
118 	config_items_t *prev;
119 	config_items_t *head;
120 	char *key;
121 	char *value;
122 }
123 config_items_s;
124 
125 typedef struct config_section_s {
126 	config_section_t *head;
127 	config_section_t *next;
128 	char *sectionname;
129 	config_items_t *items;
130 }
131 config_section_s;
132 
133 typedef struct configfile_s {
134 	config_section_t *sections;
135 }
136 configfile_s;
137 
138 typedef struct plugin_info_s {
139 	/* type - see above for valid defines*/
140 	int type;
141 	/* short name of the plugin - used only for logging at the moment */
142 	char *name;
143 	/* run thread - will be called every update_msecs milliseconds*/
144 	int *(*plugin_run) (void *);
145 	unsigned int update_msecs;
146 	/* plugin process to be called on close or NULL if there isnt one*/
147 	void *(*plugin_exit) (void *);
148 	/* plugin process to be called on EVENT (such as keypress)*/
149 	int *(*event_handler) (void *);
150 	/* init func if there is one else NULL*/
151 	int *(*plugin_init) (void *);
152 	char *filename;
153 }
154 plugin_info_s;
155 
156 typedef struct plugin_s {
157 	g15daemon_t *masterlist;
158 	unsigned int type;
159 	plugin_info_t *info;
160 	void *plugin_handle;
161 	void *args;
162 }
163 plugin_s;
164 
165 typedef struct lcd_s {
166 	g15daemon_t *masterlist;
167 	int lcd_type;
168 	unsigned char buf[LCD_BUFSIZE];
169 	int max_x;
170 	int max_y;
171 	int connection;
172 	unsigned int backlight_state;
173 	unsigned int mkey_state;
174 	unsigned int contrast_state;
175 	unsigned int state_changed;
176 	/* set to 1 if user manually selected this screen 0 otherwise */
177 	unsigned int usr_foreground;
178 	/* set to 1 if screen is never to be user-selectable */
179 	unsigned int never_select;
180 	/* only used for plugins */
181 	plugin_t *g15plugin;
182 }
183 lcd_s;
184 
185 typedef struct plugin_event_s {
186 	unsigned int event;
187 	unsigned long value;
188 	lcd_t *lcd;
189 }
190 plugin_event_s;
191 
192 struct lcdnode_s {
193 	g15daemon_t *list;
194 	lcdnode_t *prev;
195 	lcdnode_t *next;
196 	lcdnode_t *last_priority;
197 	lcd_t *lcd;
198 }
199 static lcdnode_s;
200 
201 struct g15daemon_s {
202 	lcdnode_t *head;
203 	lcdnode_t *tail;
204 	lcdnode_t *current;
205 	void *(*keyboard_handler)(void*);
206 	struct passwd *nobody;
207 	volatile unsigned long numclients;
208 	configfile_t *config;
209 	unsigned int kb_backlight_state; // master state
210 	unsigned int remote_keyhandler_sock;
211 }
212 static g15daemon_s;
213 
214 static pthread_mutex_t lcdlist_mutex;
215 static pthread_mutex_t g15lib_mutex;
216 
217 /* server hello */
218 #define SERV_HELO "G15 daemon HELLO"
219 
220 #ifdef G15DAEMON_BUILD
221 /* internal g15daemon-only functions */
222 void g15daemon_init_refresh();
223 void g15daemon_quit_refresh();
224 int uf_write_buf_to_g15(lcd_t *lcd);
225 /* write a pbm format file 'filename' with image contained in 'buf' */
226 int uf_screendump_pbm(unsigned char *buf,char *filename);
227 int uf_read_keypresses(unsigned int *keypresses, unsigned int timeout);
228 /* return the pid of a running copy of g15daemon, else -1 */
229 int uf_return_running();
230 /* create a /var/run/g15daemon.pid file, returning 0 on success else -1 */
231 int uf_create_pidfile();
232 /* open & run all plugins in the given directory */
233 int g15_open_all_plugins(g15daemon_t *masterlist, char *plugin_directory);
234 /* linked lists */
235 g15daemon_t *ll_lcdlist_init();
236 void ll_lcdlist_destroy(g15daemon_t **masterlist);
237 /* open and parse config file */
238 int uf_conf_open(g15daemon_t *list, char *filename);
239 /* write the config file with all keys/sections */
240 int uf_conf_write(g15daemon_t *list,char *filename);
241 /* free all memory used by the config subsystem */
242 void uf_conf_free(g15daemon_t *list);
243 /* search the list for valid key called "key" in section named "section" return pointer to item or NULL */
244 config_items_t* uf_search_confitem(config_section_t *section, char *key);
245 /* generic handler for net clients */
246 int internal_generic_eventhandler(plugin_event_t *myevent);
247 #endif
248 
249 /* the following functions are available for use by plugins */
250 /* send notification of LCD buffer update */
251 void g15daemon_send_refresh(lcd_t *lcd);
252 /* wait on notification of LCD buffer update */
253 void g15daemon_wait_refresh();
254 /* create a new section */
255 config_section_t *g15daemon_cfg_load_section(g15daemon_t *masterlist,char *name);
256 /* return string value from key in sectionname */
257 char* g15daemon_cfg_read_string(config_section_t *section, char *key, char *defaultval);
258 /* return float from key in sectionname */
259 double g15daemon_cfg_read_float(config_section_t *section, char *key, double defaultval);
260 /* return int from key in sectionname */
261 int g15daemon_cfg_read_int(config_section_t *section, char *key, int defaultval);
262 /* return bool as int from key in sectionname */
263 int g15daemon_cfg_read_bool(config_section_t *section, char *key, int defaultval);
264 /* add a new key, or update the value of an already existing key, or return -1 if section doesnt exist */
265 int g15daemon_cfg_write_string(config_section_t *section, char *key, char *val);
266 int g15daemon_cfg_write_float(config_section_t *section, char *key, double val);
267 int g15daemon_cfg_write_int(config_section_t *section, char *key, int val);
268 /* simply write value as On or Off depending on whether val>0 */
269 int g15daemon_cfg_write_bool(config_section_t *section, char *key, unsigned int val);
270 /* remoe a key/value pair from named section */
271 int g15daemon_cfg_remove_key(config_section_t *section, char *key);
272 /* send event to foreground client's eventlistener */
273 int g15daemon_send_event(void *caller, unsigned int event, unsigned long value);
274 /* open named plugin */
275 void * g15daemon_dlopen_plugin(char *name,unsigned int library);
276 /* close plugin with handle <handle> */
277 int g15daemon_dlclose_plugin(void *handle) ;
278 /* syslog wrapper */
279 int g15daemon_log (int priority, const char *fmt, ...);
280 /* cycle from displayed screen to next on list */
281 void g15daemon_lcdnode_cycle(g15daemon_t *masterlist);
282 /* add new screen */
283 lcdnode_t *g15daemon_lcdnode_add(g15daemon_t **masterlist) ;
284 /* remove screen */
285 void g15daemon_lcdnode_remove (lcdnode_t *oldnode);
286 /* handy function from xine_utils.c */
287 void *g15daemon_xmalloc(size_t size) ;
288 /* threadsafe sleep */
289 void g15daemon_sleep(int seconds);
290 /* threadsafe millisecond sleep */
291 int g15daemon_msleep(int milliseconds) ;
292 /* return current time in milliseconds */
293 unsigned int g15daemon_gettime_ms();
294 /* convert 1byte/pixel buffer to internal g15 format */
295 void g15daemon_convert_buf(lcd_t *lcd, unsigned char * orig_buf);
296 #endif
297