1 /***************************************************************************
2 lineak_core_functions.cpp - description
3 -------------------
4 begin : Mon Feb 10 2003
5 copyright : (C) 2003 by Sheldon Lee Wen
6 email : leewsb@hotmail.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 #include <lineak/lineak_core_functions.h>
18
19 #include <fstream>
20 #include <iostream>
21 #include <sstream>
22 #include <cstdlib>
23 #include <stdlib.h>
24 #include <unistd.h>
25
26
27
28 extern "C" {
29 #ifdef HAVE_GETOPT_H
30 # define HAVE_GETOPT_LONG
31 # include <getopt.h>
32 #endif
33 #ifndef X_NOT_STDC_ENV
34 # include <stdlib.h>
35 #else
36 extern char *getenv();
37 #endif
38
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <dirent.h>
42 #include <stdio.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <signal.h>
46 #include <pthread.h>
47 #include <semaphore.h>
48
49 #include <X11/Xlib.h>
50 }
51
52 #include <lineak/definitions.h>
53 #include <lineak/saver.h>
54 #include <lineak/configloader.h>
55 #include <lineak/lineak_util_functions.h>
56 #include <lineak/defloader.h>
57 #include <lineak/ldef.h>
58 #include <lineak/lkbd.h>
59 #include <lineak/lkey.h>
60 #include <lineak/lockctrl.h>
61 #include <lineak/lcommand.h>
62 #include <lineak/msgpasser.h>
63 #include <lineak/lobject.h>
64
65 //#include "commandexec.h"
66
67 extern bool verbose;
68 extern bool very_verbose;
69
70 using namespace lineak_util_functions;
71 using namespace std;
72
73
msg(const string message)74 void lineak_core_functions::msg(const string message) {
75 lineak_core_functions::msg(message.c_str());
76 }
error(const string message)77 void lineak_core_functions::error(const string message) {
78 lineak_core_functions::error(message.c_str());
79 }
fatal(const string message)80 void lineak_core_functions::fatal(const string message) {
81 lineak_core_functions::fatal(message.c_str());
82 }
83
vmsg(const string message)84 void lineak_core_functions::vmsg(const string message) {
85 lineak_core_functions::vmsg(message.c_str());
86 }
verror(const string message)87 void lineak_core_functions::verror(const string message) {
88 lineak_core_functions::verror(message.c_str());
89 }
vfatal(const string message)90 void lineak_core_functions::vfatal(const string message) {
91 lineak_core_functions::vfatal(message.c_str());
92 }
93
msg(const char * message)94 void lineak_core_functions::msg(const char* message) {
95 if (verbose) {
96 cout << message << endl;
97 }
98 }
error(const char * message)99 void lineak_core_functions::error(const char* message) {
100 if (verbose) {
101 cerr << message << endl;
102 }
103 }
fatal(const char * message)104 void lineak_core_functions::fatal(const char* message) {
105 if (verbose) {
106 cerr << "Fatal Error: " << message << endl;
107 msgPasser message;
108 message.start();
109 message.sendMessage(msgPasser::EXIT,"exit");
110 }
111 }
112
vmsg(const char * message)113 void lineak_core_functions::vmsg(const char* message) {
114 if (very_verbose) {
115 cout << message << endl;
116 }
117 }
verror(const char * message)118 void lineak_core_functions::verror(const char* message) {
119 if (very_verbose) {
120 cerr << message << endl;
121 }
122 }
vfatal(const char * message)123 void lineak_core_functions::vfatal(const char* message) {
124 if (very_verbose) {
125 cerr << "Fatal Error: " << message << endl;
126 msgPasser message;
127 message.start();
128 message.sendMessage(msgPasser::EXIT,"exit");
129 }
130 }
131
132 /* Parse the configuration file.
133 prefs: is a ConfigDirectives object. It is loaded with values obtained from the command line, and
134 other system directives and defaults.
135 In this function, it can contain an alternative location for the users config file.
136 myConfig: is a configuration object. It will be loaded with values from the config loader.
137
138 Return false if we should exist b/c no config file exists, or we could not load
139 any configuration information.
140 Return true if we were successful in loading configuration information.
141 */
142
parseconffile(ConfigDirectives & prefs,LConfig & myConfig)143 bool lineak_core_functions::parseconffile(ConfigDirectives & prefs, LConfig & myConfig) {
144 string conffilename;
145 string homedir = getenv("HOME");
146 /* set (globally) full path of config file ($HOME/.lineak/CONFIGFILE) */
147 if (prefs.getValue(_CD_USERCONFFILE) == snull) {
148 if (!dir_exists(homedir + LINEAKDIR))
149 create_homedir();
150 conffilename = homedir + CONFFILE;
151 } else
152 conffilename = prefs.getValue(_CD_USERCONFFILE);
153
154 /* does the file exist? */
155 if (conffilename == snull || !file_exists(conffilename)) {
156 conffilename = SYS_CONFFILE;
157 if (!file_exists(conffilename)) {
158 /* file does not exist */
159 cerr << "*** A configuration file was not found! ***" << endl;
160 cerr << " Please run lineakd -l to list the supported keyboards." << endl;
161 cerr << " Then run \"lineakd -c TYPE\" to create a configuration file for your keyboard." << endl;
162 cerr << " Once that is done, edit " << (homedir + CONFFILE) << " or " << SYS_CONFFILE << " to map your keys to commands, then run lineakd again." << endl;
163 return(false);
164 }
165 }
166 //FIXME: reconcile command line directives, with directives and defaults from the plugins, as well as our program
167 // directives and defaults. Then pass them here to the configldr object.
168 // prefs at this point is made up of first: directives and defaults from all of the plugins.
169 // second: any values specified on the command line are added to or overwrite the values in the directives and defaults.
170 // Now, we will pass this to the configloader, who will likewise overwrite and
171 vmsg("Instantiating ConfigLoader");
172 msg("Loading a config file");
173 //prefs.print(cout);
174 msg("conffilename = :" + conffilename);
175 ConfigLoader configldr(conffilename, prefs);
176 //cout << "Loading a config file. Got a configldr\n";
177 //(configldr.loadConfig()).print(cout);
178 //cout << "Doing it again.\n" << endl;
179 //configldr >> myConfig;
180 myConfig = configldr.loadConfig();
181 //sleep(2);
182 msg("Displaying config.");
183 if (verbose)
184 myConfig.print(cout);
185
186 vmsg("Checking to see if it is empty");
187 if (myConfig.isEmpty()) {
188 cerr << "*** Configuration file " << conffilename << " could not be loaded" << endl;
189 cerr << " Have you defined actions for your keys?" << endl;
190 return(false);
191 }
192 vmsg("Returning from parseconffile");
193 return (true);
194 }
195
196 /* Parse the keyboard definition file.
197 prefs: is a ConfigDirectives object. It can be loaded with values obtained from the command line
198 or loaded with other relavant values from another program. In this function, it can contain
199 an alternative locations for the user and the system definitions files.
200
201 Return false if we should exit b/c of no definitions loaded.
202 Return true if we are all good. */
parsedeffile(ConfigDirectives & prefs,LDef & def)203 bool lineak_core_functions::parsedeffile(ConfigDirectives & prefs, LDef & def) {
204 string usrdeffilename = prefs.getValue(_CD_USERDEFFILE); //userdefconf;
205 string deffilename = prefs.getValue(_CD_SYSDEFFILE); //defconf;
206 string homedir = getenv("HOME");
207 LDef udef;
208
209 if (!dir_exists(homedir + LINEAKDIR))
210 create_homedir();
211
212 if (usrdeffilename == snull) {
213 usrdeffilename = homedir + LINEAKDIR;
214 usrdeffilename += DEFFILE;
215 }
216
217 if (file_exists(usrdeffilename)) {
218 msg("Parsing: " + usrdeffilename);
219 /* it exists, parse the contents */
220 DefLoader defldr(usrdeffilename);
221 udef = defldr.loadDef();
222 if ( udef.isEmpty() )
223 /* error parsing file */
224 cerr << "*** Error occurred while reading definition data from " << usrdeffilename << endl;
225 }
226
227 if (deffilename == snull ) {
228 /* SET full path of definition files ($sysconfdir/lineakkb.def) */
229 deffilename = CONFDIR;
230 deffilename += "/";
231 deffilename += DEFFILE;
232 }
233
234 if ( deffilename != usrdeffilename ) {
235 msg("Parsing: " + deffilename);
236 /* does the file exist? */
237 if (file_exists(deffilename)) {
238 /* it exists, parse the contents */
239 DefLoader sysdefldr(deffilename);
240 def = sysdefldr.loadDef();
241 if ( def.isEmpty() ) {
242 /* error parsing file */
243 cerr << "*** Error occurred while reading definition data from " << deffilename << endl;
244 }
245 }
246 }
247
248 /* If we cannot load any keyboard definitions */
249 if ( def.isEmpty() && udef.isEmpty() ) {
250 /* file does not exist */
251 cerr << "*** FATAL ERROR: No keyboard defintions could be loaded!" << endl;
252 return(false);
253 }
254 if (!udef.isEmpty()) {
255 /** Append the user definition data to the system data */
256 def.addKeyboards(udef);
257 }
258 vmsg("Outputting the definition file!");
259 if (very_verbose) cout << def;
260 return (true);
261 }
262 /*
263 void lineak_core_functions::showplugins(PluginManager & plugins) {
264 cout << "\nLinEAK v" << VERSION << " -- Loaded Plugins:\n" << endl;
265 vector<string>::iterator it = plugins.begin();
266 while (it != plugins.end()) {
267 cout << " " << *it << endl;
268 it++;
269 }
270 cout << endl;
271 cout << "\nLinEAK v" << VERSION << " -- Loaded Macros:\n" << endl;
272 it = macros.begin();
273 while (it != macros.end()) {
274 cout << " " << *it << endl;
275 it++;
276 }
277 }
278 */
showkeyboards(LDef & def)279 void lineak_core_functions::showkeyboards(LDef & def) {
280 map<string,LKbd*> &tmp = def.getTable();
281
282 cout << "\nLinEAK v" << VERSION << " -- supported keyboards:\n" << endl;
283 cout << " [TYPE]\t\t[Full name]\n" << endl;
284 for (map<string,LKbd*>::const_iterator m = tmp.begin(); m != tmp.end(); m++) {
285 if (m->first != snull)
286 printf(" %s%s%s %s\n",(m->first).c_str(),strlen((m->first).c_str())>=7?"\t":"\t\t",strcasecmp(strip((m->second)->brand, "\"").c_str(),"other")==0?"":strip((m->second)->brand, "\"").c_str(),strip((m->second)->model, "\"").c_str());
287 }
288 }
create_homedir(void)289 void lineak_core_functions::create_homedir(void) {
290 string picsdir;
291 string homedir = getenv("HOME");
292 /** Make sure that the ~/.lineak directory exists */
293 string lineakdir = homedir + LINEAKDIR;
294 if (!dir_exists(lineakdir)) {
295 if (mkdir(lineakdir.c_str(), 0755) == -1) {
296 cout << "*** FATAL ERROR: unable to create directory" << lineakdir << endl;
297 exit(1);
298 }
299 }
300 picsdir = homedir + PICSDIR;
301 if (!dir_exists(picsdir)) {
302 if (mkdir(picsdir.c_str(), 0755) == -1) {
303 cout << "*** ERROR: unable to create directory" << picsdir << endl;
304 }
305 }
306 }
307 /** We assume at this point that the global definitions objects are created */
create_new_conf(ConfigDirectives & prefs,LDef & def)308 void lineak_core_functions::create_new_conf(ConfigDirectives & prefs, LDef & def) {
309 //string conffilename = prefs.getValue("conffilename");
310 //string cdromdev = prefs.getValue("CdromDevice");
311 //string mixdev = prefs.getValue("MixerDevice");
312 //LDef def = idef;
313 string homedir = getenv("HOME");
314 string kbtype = prefs.getValue(_CD_KEYBOARD_TYPE);
315
316 LCommand blank;
317 LConfig config;
318
319 // Make sure we have definitions loaded and the kbtype is not empty.
320 if (def.isEmpty() || kbtype == snull) {
321 cerr << "Attempting to create a config file with no keyboard definitions loaded" << endl;
322 exit(false);
323 }
324 // Attempt to get the definition for the keyboard.
325 if (!def.hasKeyboard(kbtype)) {
326 cerr << "*** ERROR: Invalid keyboard type: " << kbtype<< " \nTo find out the supported keyboard types, use: 'lineakd -l'\n" << endl;
327 exit(false);
328 }
329 create_homedir();
330 /* set (globally) full path of config file ($HOME/.lineak/CONFIGFILE) */
331 if (prefs.getValue(_CD_USERCONFFILE) == snull)
332 prefs.addValue(_CD_USERCONFFILE, string(homedir + CONFFILE));
333
334 /* no CD-ROM device specified? */
335 // if (cdromdev == snull) {
336 // cout << "*** No CD-ROM device specified, using the default /dev/cdrom" << endl;
337 // cdromdev = DEFAULT_CDROM_DEVICE;
338 // }
339 /* no mixer device specified? */
340 // if (mixdev == snull) {
341 // cout << "*** No mixer device specified, using the default /dev/mixer" << endl;
342 // mixdev = DEFAULT_MIXER_DEVICE;
343 // }
344
345 //cout << "create_new_conf: kbtype = " << kbtype << endl;
346 //cout << "printing prefs from create_new_conf" << endl;
347 //cout << prefs << endl;
348 //cout << "printing defs from create_new_conf" << endl;
349 //cout << def << endl;
350
351 config = LConfig (prefs);
352
353 LKbd & kbd = def.getKeyboard(kbtype);
354 keycommand_info info;
355 /** const map< string, LObject*> & keytable = kbd.getObjects(); */
356 /** Setup the keyboard objects in the kbd object */
357 /**
358 for (map< string, LObject*>::const_iterator m = keytable.begin(); m != keytable.end(); m++) {
359 info.config_name = m->first;
360 info.parsed_name = m->first;
361 info.modifiers = 0;
362 info.command = blank;
363 config.addKeycomm(m->first,info);
364 }*/
365 const vector<string> keylist = kbd.getNames();
366 for (vector<string>::const_iterator m = keylist.begin(); m != keylist.end(); m++) {
367 info.config_name = *m;
368 info.parsed_name = *m;
369 info.modifiers = 0;
370 info.command = blank;
371 config.addKeycomm(*m,info);
372 }
373 Saver tmp(config.getFilename());
374
375 if (!tmp.saveFile(config))
376 exit(false);
377 else {
378 cout << "\n*** Creating fresh configuration in " << config.getFilename() << "\n for keyboard type: " << kbtype << endl;
379 cout << "NOTE: Now please edit the file and bind commands to the keys,\n or use klineakconfig :)\n" << endl;
380 }
381 //cout << "create_new_conf: kbtype = " << kbtype << endl;
382 //cout << "printing prefs from create_new_conf second time" << endl;
383 //cout << prefs << endl;
384 //cout << "printing defs from create_new_conf second time" << endl;
385 //cout << def << endl;
386 //cout << "printing config from create_new_conf second time" << endl;
387 //cout << config << endl;
388
389 }
390
391 /* check if there's already a running lineakd for this $USER */
is_running(string process)392 bool lineak_core_functions::is_running(string process) {
393 uid_t myuid;
394 pid_t mypid, pid;
395 DIR *dir;
396 struct dirent *d;
397 struct stat s;
398 string str, path;
399
400 mypid = getpid();
401 myuid = getuid();
402
403 if ((dir = opendir("/proc")) == NULL)
404 {
405 cout << "Cannot open /proc" << endl;
406 return -1;
407 }
408
409 if (verbose)
410 cout << "Looking for " << process << endl;
411
412 while ((d = readdir(dir)) != NULL)
413 {
414 // See if this is a process
415 if ((pid = atoi(d->d_name)) == 0)
416 continue;
417 //if (verbose) cout << "pid = " << pid << " mypid = " << mypid << endl;
418 // Ignore the pid of the current running process
419 if (pid == mypid) {
420 //if (verbose) cout << "oops it's me, moving on." << endl;
421 continue;
422 }
423
424 path = "/proc/" + string(d->d_name) + "/stat";
425
426 // Only processes with the same UID as the current running process
427 if (stat(path.c_str(), &s) != 0 && s.st_uid != myuid)
428 continue;
429
430 // Open the status file and verify the program name
431 ifstream in(path.c_str());
432 if (in.is_open()) {
433 in >> str;
434 in >> str;
435 in.close();
436 // if (verbose)
437 // cout << "Stat: " << str << endl;
438
439 // Only look for the first 15 characters as linux cuts off the stat entries after 15 characters.
440 if (str.find("(" + process.substr(0,15)) != string::npos && (mypid != pid)) {
441 if (verbose) cout << "*** " << process << " is running (pid " << pid << ")" << endl;
442 if (verbose) cout << "*** mypid: " << mypid << endl;
443 if (verbose) cout << str << endl;
444 // turn this on to see what the situation is like when we are starting.
445 /* for (int i=0; i != 50; i++) {
446 sleep (5);
447 } */
448 return true;
449 }
450 }
451 }
452 return false;
453 }
getModifierString(unsigned int imod)454 string lineak_core_functions::getModifierString(unsigned int imod) {
455 // Print out the modifiers
456 string modifier_string[] = { "control", "shift", "alt", "mod2", "mod3", "mod4", "mod5"};
457 string str = "";
458
459 if (imod & ControlMask)
460 {
461 if (str[0])
462 str+="+";
463 str+=modifier_string[0];
464 }
465 if (imod & ShiftMask)
466 {
467 if (str[0])
468 str+="+";
469 str+=modifier_string[1];
470 }
471 if (imod & Mod1Mask)
472 {
473 if (str[0])
474 str+="+";
475 str+=modifier_string[2];
476 }
477 if (imod & Mod2Mask)
478 {
479 if (str[0])
480 str+="+";
481 str+=modifier_string[3];
482 }
483 if (imod & Mod3Mask)
484 {
485 if (str[0])
486 str+="+";
487 str+=modifier_string[4];
488 }
489 if (imod & Mod4Mask)
490 {
491 if (str[0])
492 str+="+";
493 str+=modifier_string[5];
494 }
495 if (imod & Mod5Mask)
496 {
497 if (str[0])
498 str+="+";
499 str+=modifier_string[6];
500 }
501 return str;
502 }
getEventTypeString(EventType_t event_type)503 string lineak_core_functions::getEventTypeString(EventType_t event_type) {
504 switch (event_type) {
505 case PRESS:
506 return "PRESS";
507 break;
508 case RELEASE:
509 return "RELEASE";
510 break;
511 default:
512 return "UNKNOWN";
513 }
514 return "UNKNOWN";
515 }
getEventType(string event_type)516 EventType_t lineak_core_functions::getEventType(string event_type) {
517 if (event_type == "PRESS")
518 return PRESS;
519 if (event_type == "RELEASE")
520 return RELEASE;
521 //Return an unknown
522 return UNKNOWN_EVENT;
523 }
getTypeString(KeyType_t type)524 string lineak_core_functions::getTypeString(KeyType_t type) {
525 switch (type) {
526 case SYM:
527 return "SYM";
528 break;
529 case CODE:
530 return "CODE";
531 break;
532 case BUTTON:
533 return "BUTTON";
534 break;
535 default:
536 return "UNKNOWN";
537 }
538 return "UNKNOWN";
539 }
getType(string type)540 KeyType_t lineak_core_functions::getType(string type) {
541 if (type == "SYM")
542 return SYM;
543 if (type == "CODE")
544 return CODE;
545 if (type == "BUTTON")
546 return BUTTON;
547 return UNKNOWN_KEY;
548 }
getModifierNumericValue(const string modstr)549 unsigned int lineak_core_functions::getModifierNumericValue(const string modstr) {
550 string modifiers = modstr;
551 unsigned int modifier = 0;
552 string::size_type j = 0;
553 vector<string> mods;
554
555 // If there is no modifier, return 0
556 if ( modstr == "" || modstr == "default" )
557 return 0;
558
559 // Add a '+' to the end so we have something to parse on in the
560 // following while loop in the event that there is only one modifier.
561 if (modifiers[modifiers.size()-1] != '+') {
562 modifiers += '+';
563 }
564 // Break the string up and put the individual modifiers into a vector
565 // of strings.
566 while (modifiers.find('+') != string::npos) {
567 j = modifiers.find('+');
568 //cout << "adding modifier: " << modifiers.substr(0,j) << " to key:" << keyname << endl;
569 mods.push_back(modifiers.substr(0,j));
570 modifiers.erase(0,j+1);
571 }
572 for (vector<string>::iterator it = mods.begin(); it != mods.end(); it++) {
573
574 /* build the modifier */
575 if (*it == "control" || *it == "Control_L" || *it == "Control_R" )
576 modifier |= ControlMask;
577 else if (*it == "shift" || *it == "Shift_L" || *it == "Shift_R" )
578 modifier |= ShiftMask;
579 else if (*it == "mod1" || *it == "alt" || *it == "Alt_L" || *it == "Alt_R" ) {
580 modifier |= Mod1Mask;
581 //cout << "adding Mod1Mask modifier to " << keyname << endl;
582 }
583 else if (*it == "mod2")
584 modifier |= Mod2Mask;
585 else if (*it == "mod3")
586 modifier |= Mod3Mask;
587 else if (*it == "mod4")
588 modifier |= Mod4Mask;
589 else if (*it == "mod5")
590 modifier |= Mod5Mask;
591 //else if (*it == "release")
592 // event_type = RELEASE;
593 //else
594 //{
595 //type = SYM;
596 //keysym = XStringToKeysym (line2);
597 //if (keysym == 0)
598 //break;
599 //}
600 /* build the modifier */ /*
601 if (strcmp_nocase(*it,"control"))
602 modifier |= ControlMask;
603 else if (strcmp_nocase(*it,"shift"))
604 modifier |= ShiftMask;
605 else if (strcmp_nocase(*it,"mod1") || strcmp_nocase(*it, "alt")) {
606 modifier |= Mod1Mask;
607 //cout << "adding Mod1Mask modifier to " << keyname << endl;
608 }
609 else if (strcmp_nocase(*it,"mod2"))
610 modifier |= Mod2Mask;
611 else if (strcmp_nocase(*it,"mod3"))
612 modifier |= Mod3Mask;
613 else if (strcmp_nocase(*it,"mod4"))
614 modifier |= Mod4Mask;
615 else if (strcmp_nocase(*it,"mod5"))
616 modifier |= Mod5Mask;
617 */
618 }
619 return modifier;
620 }
621
enable_IBMRA7993(void)622 void lineak_core_functions::enable_IBMRA7993(void) {
623 lineak_core_functions::send_commands("send_to_keyboard", "ea 71");
624 }
625
send_commands(string command,string args)626 void lineak_core_functions::send_commands(string command, string args) {
627 string comm;
628 //comm += SBINDIR;
629 //comm += "/";
630 comm += command;
631 comm += " ";
632 comm += args;
633 comm += " &";
634
635 if (!fork()) {
636
637 /* child process that tries to run the command, and then exits */
638 /* all specials done, let's go for it... ;) */
639 if (verbose) cout << "... running " << comm << endl;
640 //system("which setkeycodes");
641 system(comm.c_str());
642 exit(true);
643 }
644
645 }
646
647