diff --git a/contrib/AndrewFoss/README b/contrib/AndrewFoss/README new file mode 100644 index 0000000..ead5db4 --- /dev/null +++ b/contrib/AndrewFoss/README @@ -0,0 +1,28 @@ +What do these patches do ? +========================== + +1. HKEY - Hybrid Right/Left Key option in LCDd.conf + +If selected, the same config works on 4 or 6 key pads, any key wakes up +the menus, the keys behave a bit more intuitively and if you have a menu +w/ only ring or slider you can't get stuck in them on a 4 key system. +Ultimately, I wonder if the key processing could be simplified a bit, it +currently has 3 levels, that might be able to be flattened, I've been +pondering it and don't have a simple sol'n yet, but feel like there's +one there, so I'll keep thinking on it for now. + +2. OPT - adds options to the LCDd.conf for; +storing the default display string on the CFontz633.c, we use this to +put up a "starting" message for reboot for example. +setting the main menu name - which show's up on the LCD menu list, we +give it a more meaningful name like "admin" for the menus, instead of +"lcdproc" +setting the goodbye msg - which we set to "shutting down", instead of +"Thanks for using lcdproc+linux" + +3. SEG - adds the ability to get a stack trace for the LCDd daemon. I +didn't actually catch a useful trace w/ it, but might be a nice +diagnostic ability or not worth the trouble, maybe gdb's just easier +when you need? + + diff --git a/contrib/AndrewFoss/lcdprocserverHKEY.diff b/contrib/AndrewFoss/lcdprocserverHKEY.diff new file mode 100644 index 0000000..83ccae3 --- /dev/null +++ b/contrib/AndrewFoss/lcdprocserverHKEY.diff @@ -0,0 +1,547 @@ +diff --exclude='*.wanjet' --exclude='.??*' --exclude=config.h --exclude='*.orig' --exclude=Makefile --exclude='*.o' --exclude=Doxyfile --exclude='*.a' --exclude=config.log --exclude=config.status --exclude='init-*' -Nuarp server/menu.c server.HKEY/menu.c +--- server/menu.c 2006-01-26 19:47:59.000000000 -0800 ++++ server.HKEY/menu.c 2006-02-21 09:21:25.000000000 -0800 +@@ -39,6 +39,13 @@ + #include "screen.h" + #include "widget.h" + ++#ifndef HKEY //hybrid keys ++#include "shared/configfile.h" ++ ++extern int hybrid_left_key; ++extern int hybrid_right_key; ++#endif //HKEY ++ + /** Basicly a patched version of LL_GetByIndex() that ignores hidden + * entries completely. (But it takes a menu as an argument.) */ + static void * +@@ -559,12 +566,86 @@ MenuResult menu_process_input(Menu *menu + return MENURESULT_ERROR; + + switch (token) { ++ case MENUTOKEN_LEFT: ++ if (!extended) ++ return MENURESULT_NONE; ++#ifndef HKEY //hybrid key left ++ /* ++ * hybrid left key just fall through to menu key ++ */ ++ if (!hybrid_left_key) { ++ subitem = menu_get_subitem (menu, menu->data.menu.selector_pos); ++ if (subitem == NULL) ++ break; ++ switch (subitem->type) { ++ case MENUITEM_CHECKBOX: ++ /* note: this dangerous looking code works since ++ * CheckboxValue is an enum >= 0. */ ++ if (subitem->data.checkbox.allow_gray) { ++ subitem->data.checkbox.value = (subitem->data.checkbox.value - 1) % 3; ++ } ++ else { ++ subitem->data.checkbox.value = (subitem->data.checkbox.value - 1) % 2; ++ } ++ if (subitem->event_func) ++ subitem->event_func (subitem, MENUEVENT_UPDATE); ++ return MENURESULT_NONE; ++ case MENUITEM_RING: ++ /* ring: jump to the end if beginning is reached */ ++ subitem->data.ring.value = (subitem->data.ring.value < 1) ++ ? LL_Length (subitem->data.ring.strings) - 1 ++ : (subitem->data.ring.value - 1) % LL_Length (subitem->data.ring.strings); ++ if (subitem->event_func) ++ subitem->event_func (subitem, MENUEVENT_UPDATE); ++ return MENURESULT_NONE; ++ default: ++ break; ++ } ++ return MENURESULT_NONE; ++ } ++#endif //HKEY + case MENUTOKEN_MENU: + subitem = menu_get_item_for_predecessor_check(menu); + if ( ! subitem) + return MENURESULT_ERROR; + return menuitem_predecessor2menuresult( + subitem->predecessor_id, MENURESULT_CLOSE); ++ case MENUTOKEN_RIGHT: ++#ifndef HKEY //hybrid key right ++ /* ++ * hybrid right key just fall through to enter key ++ */ ++ if (!hybrid_right_key) { ++ if (!extended) /* Can you get a MENUTOKEN_RIGHT w/o a RightKey defined, this code maybe be unecessary */ ++ return MENURESULT_NONE; ++ ++ subitem = menu_get_subitem(menu, menu->data.menu.selector_pos); ++ if (subitem == NULL) ++ break; ++ switch (subitem->type) { ++ case MENUITEM_CHECKBOX: ++ if (subitem->data.checkbox.allow_gray) { ++ subitem->data.checkbox.value = (subitem->data.checkbox.value + 1) % 3; ++ } ++ else { ++ subitem->data.checkbox.value = (subitem->data.checkbox.value + 1) % 2; ++ } ++ if (subitem->event_func) ++ subitem->event_func (subitem, MENUEVENT_UPDATE); ++ return MENURESULT_NONE; ++ case MENUITEM_RING: ++ subitem->data.ring.value = (subitem->data.ring.value + 1) % LL_Length (subitem->data.ring.strings); ++ if (subitem->event_func) ++ subitem->event_func (subitem, MENUEVENT_UPDATE); ++ return MENURESULT_NONE; ++ case MENUITEM_MENU: ++ return MENURESULT_ENTER; ++ default: ++ break; ++ } ++ return MENURESULT_NONE; ++ } ++#endif //HKEY + case MENUTOKEN_ENTER: + subitem = menu_get_subitem (menu, menu->data.menu.selector_pos); + if (!subitem) +@@ -609,6 +690,18 @@ MenuResult menu_process_input(Menu *menu + menu->data.menu.scroll --; + } + else if (menu->data.menu.selector_pos == 0) { ++#ifndef HKEY //hybrid key left ++ if ( hybrid_left_key ) { ++ /* ++ * If this menu has only checkbox's and/or rings ++ * need a key to get back from this menu on a 4 key pad ++ */ ++ subitem = menu_get_item_for_predecessor_check(menu); ++ if ( subitem && ((subitem->type == MENUITEM_CHECKBOX) || (subitem->type == MENUITEM_RING))) ++ return menuitem_predecessor2menuresult( ++ subitem->predecessor_id, MENURESULT_CLOSE); ++ } ++#endif // HKEY + // wrap around to last menu entry + menu->data.menu.selector_pos = menu_visible_item_count(menu) - 1; + menu->data.menu.scroll = menu->data.menu.selector_pos + 2 - display_props->height; +@@ -626,67 +719,6 @@ MenuResult menu_process_input(Menu *menu + menu->data.menu.scroll = 0; + } + return MENURESULT_NONE; +- case MENUTOKEN_LEFT: +- if (!extended) +- return MENURESULT_NONE; +- +- subitem = menu_get_subitem (menu, menu->data.menu.selector_pos); +- if (subitem == NULL) +- break; +- switch (subitem->type) { +- case MENUITEM_CHECKBOX: +- /* note: this dangerous looking code works since +- * CheckboxValue is an enum >= 0. */ +- if (subitem->data.checkbox.allow_gray) { +- subitem->data.checkbox.value = (subitem->data.checkbox.value - 1) % 3; +- } +- else { +- subitem->data.checkbox.value = (subitem->data.checkbox.value - 1) % 2; +- } +- if (subitem->event_func) +- subitem->event_func (subitem, MENUEVENT_UPDATE); +- return MENURESULT_NONE; +- case MENUITEM_RING: +- /* ring: jump to the end if beginning is reached */ +- subitem->data.ring.value = (subitem->data.ring.value < 1) +- ? LL_Length (subitem->data.ring.strings) - 1 +- : (subitem->data.ring.value - 1) % LL_Length (subitem->data.ring.strings); +- if (subitem->event_func) +- subitem->event_func (subitem, MENUEVENT_UPDATE); +- return MENURESULT_NONE; +- default: +- break; +- } +- return MENURESULT_NONE; +- case MENUTOKEN_RIGHT: +- if (!extended) +- return MENURESULT_NONE; +- +- subitem = menu_get_subitem(menu, menu->data.menu.selector_pos); +- if (subitem == NULL) +- break; +- switch (subitem->type) { +- case MENUITEM_CHECKBOX: +- if (subitem->data.checkbox.allow_gray) { +- subitem->data.checkbox.value = (subitem->data.checkbox.value + 1) % 3; +- } +- else { +- subitem->data.checkbox.value = (subitem->data.checkbox.value + 1) % 2; +- } +- if (subitem->event_func) +- subitem->event_func (subitem, MENUEVENT_UPDATE); +- return MENURESULT_NONE; +- case MENUITEM_RING: +- subitem->data.ring.value = (subitem->data.ring.value + 1) % LL_Length (subitem->data.ring.strings); +- if (subitem->event_func) +- subitem->event_func (subitem, MENUEVENT_UPDATE); +- return MENURESULT_NONE; +- case MENUITEM_MENU: +- return MENURESULT_ENTER; +- default: +- break; +- } +- return MENURESULT_NONE; + case MENUTOKEN_OTHER: + /* TODO: move to the selected number and enter it */ + return MENURESULT_NONE; +diff --exclude='*.wanjet' --exclude='.??*' --exclude=config.h --exclude='*.orig' --exclude=Makefile --exclude='*.o' --exclude=Doxyfile --exclude='*.a' --exclude=config.log --exclude=config.status --exclude='init-*' -Nuarp server/menuitem.c server.HKEY/menuitem.c +--- server/menuitem.c 2006-01-26 19:47:59.000000000 -0800 ++++ server.HKEY/menuitem.c 2006-02-21 09:22:53.000000000 -0800 +@@ -84,6 +84,10 @@ const IpSstringProperties IPinfo[] = { + { 39, ':', 16, 4, 65535, { 4096, 256, 16, 1, 0 }, "%04x", verify_ipv6, "0:0:0:0:0:0:0:0" } + }; + ++#ifndef HKEY // hybrid keys ++extern int hybrid_left_key; ++extern int hybrid_right_key; ++#endif //HKEY + + /******** MENU UTILITY FUNCTIONS ********/ + +@@ -983,26 +987,38 @@ MenuResult menuitem_process_input_slider + return MENURESULT_ERROR; + + switch (token) { +- case MENUTOKEN_MENU: +- return menuitem_predecessor2menuresult( +- item->predecessor_id, MENURESULT_CLOSE); +- case MENUTOKEN_ENTER: +- return menuitem_successor2menuresult( +- item->successor_id, MENURESULT_CLOSE); + case MENUTOKEN_UP: + case MENUTOKEN_RIGHT: +- item->data.slider.value = min (item->data.slider.maxvalue, ++#ifndef HKEY //hybrid key right ++ if ( !hybrid_right_key || token == MENUTOKEN_UP ) { ++#endif /*HKEY*/ ++ item->data.slider.value = min (item->data.slider.maxvalue, + item->data.slider.value + item->data.slider.stepsize); +- if (item->event_func) +- item->event_func (item, MENUEVENT_PLUS); +- return MENURESULT_NONE; ++ if (item->event_func) ++ item->event_func (item, MENUEVENT_PLUS); ++ return MENURESULT_NONE; ++#ifndef HKEY //hybrid key right ++ } /* hybrid right key fall through to enter */ ++#endif /*HKEY*/ ++ case MENUTOKEN_ENTER: ++ return menuitem_successor2menuresult( ++ item->successor_id, MENURESULT_CLOSE); + case MENUTOKEN_DOWN: + case MENUTOKEN_LEFT: +- item->data.slider.value = max (item->data.slider.minvalue, ++#ifndef HKEY //hybrid key left ++ if ( !hybrid_left_key || token == MENUTOKEN_DOWN ) { ++#endif /*HKEY*/ ++ item->data.slider.value = max (item->data.slider.minvalue, + item->data.slider.value - item->data.slider.stepsize); +- if (item->event_func) +- item->event_func (item, MENUEVENT_MINUS); +- return MENURESULT_NONE; ++ if (item->event_func) ++ item->event_func (item, MENUEVENT_MINUS); ++ return MENURESULT_NONE; ++#ifndef HKEY //hybrid key left ++ } /* hybrid left key fall through to menu */ ++#endif /*HKEY*/ ++ case MENUTOKEN_MENU: ++ return menuitem_predecessor2menuresult( ++ item->predecessor_id, MENURESULT_CLOSE); + case MENUTOKEN_OTHER: + default: + break; +@@ -1037,6 +1053,21 @@ MenuResult menuitem_process_input_numeri + item->data.numeric.error_code = 0; + + switch (token) { ++ case MENUTOKEN_LEFT: ++ /* The user wants to go to back a digit */ ++ if (pos > 0) { ++ item->data.numeric.edit_pos--; ++ if (item->data.numeric.edit_offs > item->data.numeric.edit_pos) ++ item->data.numeric.edit_offs = item->data.numeric.edit_pos; ++#ifndef HKEY //hybrid key left ++ if( hybrid_left_key ) return MENURESULT_NONE; ++ } ++ if( !hybrid_left_key ) return MENURESULT_NONE; ++ /* fall through to MENU */ ++#else ++ } ++ return MENURESULT_NONE; ++#endif /*HKEY*/ + case MENUTOKEN_MENU: + if (pos == 0) { + return menuitem_predecessor2menuresult( +@@ -1047,6 +1078,21 @@ MenuResult menuitem_process_input_numeri + menuitem_reset_numeric(item); + } + return MENURESULT_NONE; ++ case MENUTOKEN_RIGHT: ++ /* The user wants to go to next digit */ ++ if (str[pos] != '\0' && pos < max_len) { ++ item->data.numeric.edit_pos++; ++ if (pos >= display_props->width - 2) ++ item->data.numeric.edit_offs++; ++#ifndef HKEY //hybrid key right ++ if( hybrid_right_key ) return MENURESULT_NONE; ++ } ++ if( !hybrid_right_key ) return MENURESULT_NONE; ++ /* fall through to ENTER */ ++#else ++ } ++ return MENURESULT_NONE; ++#endif /*HKEY*/ + case MENUTOKEN_ENTER: + if ((extended) || (str[pos] == '\0')) { + int value; +@@ -1131,22 +1177,6 @@ MenuResult menuitem_process_input_numeri + } + } + return MENURESULT_NONE; +- case MENUTOKEN_RIGHT: +- /* The user wants to go to next digit */ +- if (str[pos] != '\0' && pos < max_len) { +- item->data.numeric.edit_pos++; +- if (pos >= display_props->width - 2) +- item->data.numeric.edit_offs++; +- } +- return MENURESULT_NONE; +- case MENUTOKEN_LEFT: +- /* The user wants to go to back a digit */ +- if (pos > 0) { +- item->data.numeric.edit_pos--; +- if (item->data.numeric.edit_offs > item->data.numeric.edit_pos) +- item->data.numeric.edit_offs = item->data.numeric.edit_pos; +- } +- return MENURESULT_NONE; + case MENUTOKEN_OTHER: + if (pos >= max_len) { + /* We're not allowed to add anything anymore */ +@@ -1196,6 +1226,21 @@ MenuResult menuitem_process_input_alpha + item->data.alpha.error_code = 0; + + switch (token) { ++ case MENUTOKEN_LEFT: ++ /* The user wants to go to back a digit */ ++ if (pos > 0) { ++ item->data.alpha.edit_pos--; ++ if (item->data.alpha.edit_offs > item->data.alpha.edit_pos) ++ item->data.alpha.edit_offs = item->data.alpha.edit_pos; ++#ifndef HKEY //hybrid key left ++ if( hybrid_left_key ) return MENURESULT_NONE; ++ } ++ if( !hybrid_left_key ) return MENURESULT_NONE; ++ /* fall through to MENU */ ++#else ++ } ++ return MENURESULT_NONE; ++#endif /*HKEY*/ + case MENUTOKEN_MENU: + if (pos == 0) { + return menuitem_predecessor2menuresult( +@@ -1206,6 +1251,22 @@ MenuResult menuitem_process_input_alpha + menuitem_reset_alpha(item); + } + return MENURESULT_NONE; ++ case MENUTOKEN_RIGHT: ++ /* The user wants to go to next digit */ ++ if (str[item->data.alpha.edit_pos] != '\0' && ++ pos < item->data.alpha.maxlength - 1) { ++ item->data.alpha.edit_pos++; ++ if (pos >= display_props->width - 2) ++ item->data.alpha.edit_offs++; ++#ifndef HKEY //hybrid key right ++ if( hybrid_right_key ) return MENURESULT_NONE; ++ } ++ if( !hybrid_right_key ) return MENURESULT_NONE; ++ /* fall through to ENTER */ ++#else ++ } ++ return MENURESULT_NONE; ++#endif /*HKEY*/ + case MENUTOKEN_ENTER: + if ((extended) || (str[item->data.alpha.edit_pos] == '\0')) { + /* The user completed his input */ +@@ -1278,23 +1339,6 @@ MenuResult menuitem_process_input_alpha + } + } + return MENURESULT_NONE; +- case MENUTOKEN_RIGHT: +- /* The user wants to go to next digit */ +- if (str[item->data.alpha.edit_pos] != '\0' && +- pos < item->data.alpha.maxlength - 1) { +- item->data.alpha.edit_pos++; +- if (pos >= display_props->width - 2) +- item->data.alpha.edit_offs++; +- } +- return MENURESULT_NONE; +- case MENUTOKEN_LEFT: +- /* The user wants to go to back a digit */ +- if (pos > 0) { +- item->data.alpha.edit_pos--; +- if (item->data.alpha.edit_offs > item->data.alpha.edit_pos) +- item->data.alpha.edit_offs = item->data.alpha.edit_pos; +- } +- return MENURESULT_NONE; + case MENUTOKEN_OTHER: + if (pos >= item->data.alpha.maxlength) { + /* We're not allowed to add anything anymore */ +@@ -1333,7 +1377,24 @@ MenuResult menuitem_process_input_ip (Me + item->data.ip.error_code = 0; + + switch (token) { +- case MENUTOKEN_MENU: ++ case MENUTOKEN_LEFT: ++ /* The user wants to go to back a digit */ ++ if (pos > 0) { ++ item->data.ip.edit_pos--; ++ if (str[item->data.ip.edit_pos] == ipinfo->sep) ++ item->data.ip.edit_pos--; ++ if (item->data.ip.edit_offs > item->data.ip.edit_pos) ++ item->data.ip.edit_offs = item->data.ip.edit_pos; ++#ifndef HKEY //hybrid key left ++ if( hybrid_left_key ) return MENURESULT_NONE; ++ } ++ if( !hybrid_left_key ) return MENURESULT_NONE; ++ /* fall through to MENU */ ++#else ++ } ++ return MENURESULT_NONE; ++#endif /*HKEY*/ ++ case MENUTOKEN_MENU: + if (pos == 0) { + return menuitem_predecessor2menuresult( + item->predecessor_id, MENURESULT_CLOSE); +@@ -1343,6 +1404,22 @@ MenuResult menuitem_process_input_ip (Me + menuitem_reset_ip(item); + } + return MENURESULT_NONE; ++ case MENUTOKEN_RIGHT: ++ if (pos < item->data.ip.maxlength - 1) { ++ item->data.ip.edit_pos++; ++ if (str[item->data.ip.edit_pos] == ipinfo->sep) ++ item->data.ip.edit_pos++; ++ while (item->data.ip.edit_pos - item->data.ip.edit_offs > display_props->width - 2) ++ item->data.ip.edit_offs++; ++#ifndef HKEY //hybrid key right ++ if( hybrid_right_key ) return MENURESULT_NONE; ++ } ++ if( !hybrid_right_key ) return MENURESULT_NONE; ++ /* fall through to ENTER */ ++#else ++ } ++ return MENURESULT_NONE; ++#endif /*HKEY*/ + case MENUTOKEN_ENTER: + if (extended || (pos >= item->data.ip.maxlength - 1)) { + // remove the leading spaces/zeros in each octet-representing string +@@ -1409,25 +1486,6 @@ MenuResult menuitem_process_input_ip (Me + snprintf(numstr, 5, ipinfo->format, num); + memcpy(&str[pos - (pos % (ipinfo->width + 1))], numstr, ipinfo->width); + return MENURESULT_NONE; +- case MENUTOKEN_RIGHT: +- if (pos < item->data.ip.maxlength - 1) { +- item->data.ip.edit_pos++; +- if (str[item->data.ip.edit_pos] == ipinfo->sep) +- item->data.ip.edit_pos++; +- while (item->data.ip.edit_pos - item->data.ip.edit_offs > display_props->width - 2) +- item->data.ip.edit_offs++; +- } +- return MENURESULT_NONE; +- case MENUTOKEN_LEFT: +- /* The user wants to go to back a digit */ +- if (pos > 0) { +- item->data.ip.edit_pos--; +- if (str[item->data.ip.edit_pos] == ipinfo->sep) +- item->data.ip.edit_pos--; +- if (item->data.ip.edit_offs > item->data.ip.edit_pos) +- item->data.ip.edit_offs = item->data.ip.edit_pos; +- } +- return MENURESULT_NONE; + case MENUTOKEN_OTHER: + /* process other keys */ + if ((strlen(key) == 1) && +diff --exclude='*.wanjet' --exclude='.??*' --exclude=config.h --exclude='*.orig' --exclude=Makefile --exclude='*.o' --exclude=Doxyfile --exclude='*.a' --exclude=config.log --exclude=config.status --exclude='init-*' -Nuarp server/menuscreens.c server.HKEY/menuscreens.c +--- server/menuscreens.c 2006-01-26 19:47:59.000000000 -0800 ++++ server.HKEY/menuscreens.c 2006-02-21 09:33:21.000000000 -0800 +@@ -48,6 +48,15 @@ char * down_key; + char * left_key; + char * right_key; + ++#ifndef HKEY //hybrid keys ++/* ++ * hybrid left becomes menu key at left edge of screen ++ * hybrid right becomes enter key at right edge of screen ++ */ ++int hybrid_left_key = 0; ++int hybrid_right_key = 0; ++#endif //HKEY ++ + Screen * menuscreen = NULL; + MenuItem * active_menuitem = NULL; + /** the "real" main_menu */ +@@ -91,6 +100,11 @@ int menuscreens_init() + if (tmp) + right_key = strdup(tmp); + ++#ifndef HKEY //get hybrid keys from config file ++ hybrid_right_key = config_get_bool ("menu", "HybridRightKey", 0, 0); ++ hybrid_left_key = config_get_bool ("menu", "HybridLeftKey", 0, 0); ++#endif ++ + + /* Now reserve keys */ + input_reserve_key (menu_key, true, NULL); +@@ -186,6 +200,11 @@ void menuscreen_inform_item_modified (Me + + bool is_menu_key (char * key) + { ++#ifndef HKEY //hybrid keys, any key wake-up menus ++ /* any key wakes up menus */ ++ if (key && ( hybrid_left_key || hybrid_right_key )) ++ return true; ++#endif //HKEY + if (menu_key && key && strcmp (key, menu_key) == 0) + return true; + else +@@ -466,28 +485,28 @@ void menuscreen_create_menu () + menu_add_item (options_menu, driver_menu); + if (contrast_avail) { + int contrast = driver->get_contrast(driver); +- ++ + /* menu's client is NULL since we're in the server */ + slider = menuitem_create_slider ("contrast", contrast_handler, "Contrast", +- NULL, "min", "max", 0, 1000, 25, contrast); ++ NULL, "min", "max", 0, 1000, 25, contrast); + menu_add_item (driver_menu, slider); + } + if (brightness_avail) { + int onbrightness = driver->get_brightness (driver, BACKLIGHT_ON); + int offbrightness = driver->get_brightness (driver, BACKLIGHT_OFF); +- ++ + slider = menuitem_create_slider ("onbrightness", brightness_handler, "On Brightness", +- NULL, "min", "max", 0, 1000, 25, onbrightness); ++ NULL, "min", "max", 0, 1000, 25, onbrightness); + menu_add_item (driver_menu, slider); + + slider = menuitem_create_slider ("offbrightness", brightness_handler, "Off Brightness", +- NULL, "min", "max", 0, 1000, 25, offbrightness); ++ NULL, "min", "max", 0, 1000, 25, offbrightness); + menu_add_item (driver_menu, slider); + } + } + } + +-#ifdef LCDPROC_TESTMENUS ++#ifdef LCDPROC_TESTMENUS + test_menu = menu_create ("test", NULL, "Test menu", NULL); + menu_add_item (main_menu, test_menu); + diff --git a/contrib/AndrewFoss/lcdprocserverOPT.diff b/contrib/AndrewFoss/lcdprocserverOPT.diff new file mode 100644 index 0000000..fd87b96 --- /dev/null +++ b/contrib/AndrewFoss/lcdprocserverOPT.diff @@ -0,0 +1,243 @@ +diff --exclude='*.wanjet' --exclude='.??*' --exclude=config.h --exclude='*.orig' --exclude=Makefile --exclude='*.o' --exclude=Doxyfile --exclude='*.a' --exclude=config.log --exclude=config.status --exclude='init-*' -Nuarp server/drivers/CFontz633.c server.OPT/drivers/CFontz633.c +--- server/drivers/CFontz633.c 2006-01-26 19:47:59.000000000 -0800 ++++ server.OPT/drivers/CFontz633.c 2006-02-21 19:35:27.000000000 -0800 +@@ -131,6 +131,9 @@ static void CFontz633_init_vbar (Driver + static void CFontz633_init_hbar (Driver *drvthis); + static void CFontz633_no_live_report (Driver *drvthis); + static void CFontz633_hardware_clear (Driver *drvthis); ++#ifndef OPT //store boot screen ++static void CFontz633_store_boot_state (Driver *drvthis); ++#endif //OPT + + + /* +@@ -305,6 +308,16 @@ CFontz633_init (Driver *drvthis) + CFontz633_no_live_report (drvthis); + CFontz633_hardware_clear (drvthis); + ++#ifndef OPT //store boot screen ++ /* get and store the power on boot line, repurposing the "size" buffer */ ++ strncpy(size, drvthis->config_get_string (drvthis->name, "BootDisplay", 0, "" ), sizeof(size)); ++ if ( size[0] ) { ++ CFontz633_string (drvthis, 1, 1, size); ++ CFontz633_flush (drvthis); ++ CFontz633_store_boot_state (drvthis); ++ } ++#endif //OPT ++ + report (RPT_DEBUG, "%s: done\n", __FUNCTION__); + + return 0; +@@ -1118,3 +1131,15 @@ CFontz633_string (Driver *drvthis, int x + } + } + ++#ifndef OPT //store boot screen ++/* ++ * Saves current state as boot state ++ */ ++static void ++CFontz633_store_boot_state (Driver *drvthis) ++{ ++ PrivateData *p = drvthis->private_data; ++ ++ send_zerobyte_message(p->fd, CF633_Store_Current_State_As_Boot_State); ++} ++#endif //OPT +diff --exclude='*.wanjet' --exclude='.??*' --exclude=config.h --exclude='*.orig' --exclude=Makefile --exclude='*.o' --exclude=Doxyfile --exclude='*.a' --exclude=config.log --exclude=config.status --exclude='init-*' -Nuarp server/menuscreens.c server.OPT/menuscreens.c +--- server/menuscreens.c 2006-01-26 19:47:59.000000000 -0800 ++++ server.OPT/menuscreens.c 2006-02-21 19:31:00.000000000 -0800 +@@ -48,6 +48,9 @@ char * down_key; + char * left_key; + char * right_key; + ++#ifndef OPT ++char * menuname; /* the name for the default menu */ ++#endif //OPT + Screen * menuscreen = NULL; + MenuItem * active_menuitem = NULL; + /** the "real" main_menu */ +@@ -91,6 +94,11 @@ int menuscreens_init() + if (tmp) + right_key = strdup(tmp); + ++#ifndef OPT //get main menu name and hybrid keys from config file ++ /* Get main menu name from config file */ ++ menuname = strdup (config_get_string ("menu", "menuname", 0, "LCDproc Menu")); ++#endif //OPT ++ + + /* Now reserve keys */ + input_reserve_key (menu_key, true, NULL); +@@ -437,55 +445,62 @@ void menuscreen_create_menu () + + debug (RPT_DEBUG, "%s()", __FUNCTION__); + ++#ifndef OPT //main menu name from config file ++ main_menu = menu_create ("mainmenu", NULL, menuname, NULL); ++#else //OPT + main_menu = menu_create ("mainmenu", NULL, "LCDproc Menu", NULL); ++#endif //OPT + +- options_menu = menu_create ("options", NULL, "Options", NULL); +- menu_add_item (main_menu, options_menu); +- +-#ifdef LCDPROC_TESTMENUS +- screens_menu = menu_create ("screens", NULL, "Screens", NULL); +- menu_add_item (main_menu, screens_menu); +-#endif /*LCDPROC_TESTMENUS*/ +- +- /* menu's client is NULL since we're in the server */ +- checkbox = menuitem_create_checkbox ("heartbeat", heartbeat_handler, "Heartbeat", NULL, true, heartbeat); +- menu_add_item (options_menu, checkbox); +- +- /* menu's client is NULL since we're in the server */ +- checkbox = menuitem_create_checkbox ("backlight", backlight_handler, "Backlight", NULL, true, backlight); +- menu_add_item (options_menu, checkbox); ++#ifndef OPT //Options menu display from config file ++ if ( config_get_bool ("server", "LCDOptionsMenu", 0, 0)) { ++ options_menu = menu_create ("options", NULL, "Options", NULL); ++ menu_add_item (main_menu, options_menu); ++ ++ /* menu's client is NULL since we're in the server */ ++ checkbox = menuitem_create_checkbox ("heartbeat", heartbeat_handler, "Heartbeat", NULL, true, heartbeat); ++ menu_add_item (options_menu, checkbox); ++ ++ /* menu's client is NULL since we're in the server */ ++ checkbox = menuitem_create_checkbox ("backlight", backlight_handler, "Backlight", NULL, true, backlight); ++ menu_add_item (options_menu, checkbox); ++ ++ for (driver = drivers_getfirst(); driver; driver = drivers_getnext()) { ++ int contrast_avail = (driver->get_contrast && driver->set_contrast) ? 1 : 0; ++ int brightness_avail = (driver->get_brightness && driver->set_brightness) ? 1 : 0; + +- for (driver = drivers_getfirst(); driver; driver = drivers_getnext()) { +- int contrast_avail = (driver->get_contrast && driver->set_contrast) ? 1 : 0; +- int brightness_avail = (driver->get_brightness && driver->set_brightness) ? 1 : 0; +- +- if (contrast_avail || brightness_avail) { +- /* menu's client is NULL since we're in the server */ +- driver_menu = menu_create (driver->name, NULL, driver->name, NULL); +- menu_set_association(driver_menu, driver); +- menu_add_item (options_menu, driver_menu); +- if (contrast_avail) { +- int contrast = driver->get_contrast(driver); +- ++ if (contrast_avail || brightness_avail) { + /* menu's client is NULL since we're in the server */ +- slider = menuitem_create_slider ("contrast", contrast_handler, "Contrast", +- NULL, "min", "max", 0, 1000, 25, contrast); +- menu_add_item (driver_menu, slider); +- } +- if (brightness_avail) { +- int onbrightness = driver->get_brightness (driver, BACKLIGHT_ON); +- int offbrightness = driver->get_brightness (driver, BACKLIGHT_OFF); +- +- slider = menuitem_create_slider ("onbrightness", brightness_handler, "On Brightness", +- NULL, "min", "max", 0, 1000, 25, onbrightness); +- menu_add_item (driver_menu, slider); +- +- slider = menuitem_create_slider ("offbrightness", brightness_handler, "Off Brightness", +- NULL, "min", "max", 0, 1000, 25, offbrightness); +- menu_add_item (driver_menu, slider); ++ driver_menu = menu_create (driver->name, NULL, driver->name, NULL); ++ menu_set_association(driver_menu, driver); ++ menu_add_item (options_menu, driver_menu); ++ if (contrast_avail) { ++ int contrast = driver->get_contrast(driver); ++ ++ /* menu's client is NULL since we're in the server */ ++ slider = menuitem_create_slider ("contrast", contrast_handler, "Contrast", ++ NULL, "min", "max", 0, 1000, 25, contrast); ++ menu_add_item (driver_menu, slider); ++ } ++ if (brightness_avail) { ++ int onbrightness = driver->get_brightness (driver, BACKLIGHT_ON); ++ int offbrightness = driver->get_brightness (driver, BACKLIGHT_OFF); ++ ++ slider = menuitem_create_slider ("onbrightness", brightness_handler, "On Brightness", ++ NULL, "min", "max", 0, 1000, 25, onbrightness); ++ menu_add_item (driver_menu, slider); ++ ++ slider = menuitem_create_slider ("offbrightness", brightness_handler, "Off Brightness", ++ NULL, "min", "max", 0, 1000, 25, offbrightness); ++ menu_add_item (driver_menu, slider); ++ } + } + } + } ++ if ( config_get_bool ("server", "LCDScreensMenu", 0, 0)) { ++ screens_menu = menu_create ("screens", NULL, "Screens", NULL); ++ menu_add_item (main_menu, screens_menu); ++ } ++#endif //OPT + + #ifdef LCDPROC_TESTMENUS + test_menu = menu_create ("test", NULL, "Test menu", NULL); +diff --exclude='*.wanjet' --exclude='.??*' --exclude=config.h --exclude='*.orig' --exclude=Makefile --exclude='*.o' --exclude=Doxyfile --exclude='*.a' --exclude=config.log --exclude=config.status --exclude='init-*' -Nuarp server/serverscreens.c server.OPT/serverscreens.c +--- server/serverscreens.c 2006-01-26 19:47:59.000000000 -0800 ++++ server.OPT/serverscreens.c 2006-02-21 19:27:40.000000000 -0800 +@@ -31,6 +31,12 @@ + #include "widget.h" + #include "serverscreens.h" + ++#ifndef OPT //startup screen title from config ++#include "shared/configfile.h" ++ ++char * title; ++#endif //OPT ++ + #define UNSET_INT -1 + + Screen * server_screen; +@@ -38,6 +44,7 @@ int rotate_server_screen = UNSET_INT; + + #define MAX_SERVERSCREEN_WIDTH 40 + ++ + int + server_screen_init () + { +@@ -46,6 +53,11 @@ server_screen_init () + + debug (RPT_DEBUG, "server_screen_init"); + ++#ifndef OPT //startup screen title from config ++ /* Get server title name from config file */ ++ title = strdup (config_get_string ("server", "title", 0, "LCDproc Server")); ++#endif //OPT ++ + /* Create the screen */ + server_screen = screen_create ("_server_screen", NULL); + if (!server_screen) { +@@ -77,7 +89,11 @@ server_screen_init () + w->text = malloc (MAX_SERVERSCREEN_WIDTH+1); + if (line == 1) { + w->type = WID_TITLE; ++#ifndef OPT //startup screen titel from config ++ strncpy (w->text, title, MAX_SERVERSCREEN_WIDTH); ++#else //OPT + strncpy (w->text, "LCDproc Server", MAX_SERVERSCREEN_WIDTH); ++#endif //OPT + } else { + w->text[0] = 0; + } +@@ -156,6 +172,18 @@ goodbye_screen () + char *l16 = " LCDproc! "; + #endif + ++#ifndef OPT // disable config goobye ++ char * goodbye_string; ++ ++ if ( (goodbye_string = strdup(config_get_string("server", "goodbye", 0, "")))) { ++ t20=t16=goodbye_string; ++ if (strlen(goodbye_string) > 16 ) ++ l16 = goodbye_string + 16; ++ if (strlen(goodbye_string) > 20 ) ++ l20 = goodbye_string + 20; ++ } ++#endif //OPT ++ + if( !display_props ) + return 0; + diff --git a/contrib/AndrewFoss/lcdprocserverSEG.diff b/contrib/AndrewFoss/lcdprocserverSEG.diff new file mode 100644 index 0000000..653e6b4 --- /dev/null +++ b/contrib/AndrewFoss/lcdprocserverSEG.diff @@ -0,0 +1,1165 @@ +diff --exclude='*.wanjet' --exclude='.??*' --exclude=config.h --exclude='*.orig' --exclude=Makefile --exclude='*.o' --exclude=Doxyfile --exclude='*.a' --exclude=config.log --exclude=config.status --exclude='init-*' -Nuarp server/main.c server.SEG/main.c +--- server/main.c 2006-01-26 19:47:59.000000000 -0800 ++++ server.SEG/main.c 2006-02-21 09:14:08.000000000 -0800 +@@ -164,6 +164,31 @@ static void output_GPL_notice(void); + #define CHAIN(e,f) { if( e>=0 ) { e=(f); }} + #define CHAIN_END(e,msg) { if( e<0 ) { report( RPT_CRIT,(msg)); exit(e); }} + ++#ifndef SEG //sigsegv handler for stackdump ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#define STACKDUMP_FILENAME "/tmp/LCDdStackDump" ++ ++#ifndef DWORD ++#define DWORD unsigned long ++#endif ++ ++ ++int InstallSigSegvHandler(); ++void SigSegvHandler(int nSig, siginfo_t *pSigInfo, void *pAddr); ++unsigned GetFreeMem( unsigned long* pTotalMem, unsigned long* pUsedMem, unsigned long* pFreeMem, unsigned long* pBuffers, unsigned long* pCached ); ++ ++ ++struct sigaction SigTerm; ++struct sigaction SigPipe; ++struct sigaction SigSegv; ++ ++#endif /*SEG*/ + + int + main(int argc, char **argv) +@@ -171,6 +196,10 @@ main(int argc, char **argv) + int e = 0; + pid_t parent_pid = 0; + ++#ifndef SEG //sigsegv handler for stackdump ++ InstallSigSegvHandler(); ++#endif /*SEG*/ ++ + stored_argc = argc; + stored_argv = argv; + +@@ -1012,3 +1041,100 @@ output_help_screen(void) + * help message. + */ + } ++ ++#ifndef SEG //sigsegv handler for stackdump ++int InstallSigSegvHandler() ++{ ++ SigSegv.sa_sigaction = SigSegvHandler; ++ sigemptyset( &SigSegv.sa_mask ); ++ SigSegv.sa_flags = SA_SIGINFO; ++ ++ sigaddset (&SigSegv.sa_mask, SIGINT); ++ sigaddset (&SigSegv.sa_mask, SIGTSTP); ++ sigaddset (&SigSegv.sa_mask, SIGQUIT); ++ sigaddset (&SigSegv.sa_mask, SIGTERM); ++ ++ return sigaction( SIGSEGV, &SigSegv, NULL); ++} ++ ++void SigSegvHandler(int nSig, siginfo_t *pSigInfo, void *pAddr) ++{ ++ void *array[50]; ++ size_t size; ++ char **strings; ++ size_t i; ++ ++ FILE* fd = fopen( STACKDUMP_FILENAME, "w" ); ++ DWORD dwTotalMem, dwUsedMem, dwFreeMem, dwCached, dwBuffers, dwTotalFree; ++ time_t now; ++ struct tm date_time; ++ now = time(NULL); ++ date_time = *localtime(&now); ++ fprintf( fd, "Dump Created : %s",asctime(&date_time)); ++ ++ dwTotalFree = GetFreeMem( &dwTotalMem, &dwUsedMem, &dwFreeMem, &dwBuffers, &dwCached ); ++ fprintf( fd, "Free memory %lX ......\n", dwTotalFree ); ++ ++ if ( pSigInfo->si_signo == SIGSEGV ) ++ fprintf( fd, "Segmentation fault at Address %X ......\n", (unsigned)pSigInfo->si_addr ); ++ ++ switch( pSigInfo->si_code ) ++ { ++ case SI_KERNEL: ++ fprintf( fd, "Sent by Kernel at Address %X ......\n", (unsigned)pSigInfo->si_addr ); ++ break; ++ ++ case SEGV_MAPERR: ++ fprintf( fd, "Mapping Error at Address %X ......\n", (unsigned)pSigInfo->si_addr ); ++ break; ++ ++ case SEGV_ACCERR: ++ fprintf( fd, "Permisson Error at Address %X ......\n", (unsigned)pSigInfo->si_addr ); ++ break; ++ } ++ ++ size = backtrace (array, 50); ++ strings = backtrace_symbols (array, size); ++ ++ fprintf ( fd, "Obtained %d stack frames.\n", size); ++ ++ for (i = 0; i < size; i++) ++ fprintf ( fd, "%s\n", strings[i]); ++ ++ fclose( fd ); ++ free (strings); ++ signal (nSig, SIG_DFL); ++ raise (nSig); ++} ++ ++unsigned GetFreeMem( unsigned long* pTotalMem, unsigned long* pUsedMem, unsigned long* pFreeMem, unsigned long* pBuffers, unsigned long* pCached ) ++{ ++ char buffer[1024]; ++ long garbage; ++ int nSize; ++ char* lpStr; ++ int fd = 0; ++ ++ fd = open("/proc/meminfo", O_RDONLY ); ++ ++ if ( fd > 0 ) ++ { ++ *pFreeMem = 0; ++ *pCached = 0; ++ *pBuffers = 0; ++ ++ nSize = read( fd, buffer, 1024 ); ++ close( fd ); ++ ++ lpStr = strstr( buffer, "Mem:" ); ++ if ( lpStr ) ++ sscanf( lpStr, "Mem: %lu %lu %lu %lu %lu %lu\n", pTotalMem, pUsedMem, pFreeMem, &garbage, pBuffers, pCached); ++ } ++ else ++ { ++ return 0; ++ } ++ ++ return (*pFreeMem+*pBuffers+*pCached); ++} ++#endif /*SEG*/ +diff --exclude='*.wanjet' --exclude='.??*' --exclude=config.h --exclude='*.orig' --exclude=Makefile --exclude='*.o' --exclude=Doxyfile --exclude='*.a' --exclude=config.log --exclude=config.status --exclude='init-*' -Nuarp server/main.c.org server.SEG/main.c.org +--- server/main.c.org 1969-12-31 16:00:00.000000000 -0800 ++++ server.SEG/main.c.org 2006-01-26 19:47:59.000000000 -0800 +@@ -0,0 +1,1014 @@ ++/* ++ * main.c ++ * This file is part of LCDd, the lcdproc server. ++ * ++ * This file is released under the GNU General Public License. Refer to the ++ * COPYING file distributed with this package. ++ * ++ * Copyright (c) 1999, William Ferrell, Scott Scriven ++ * 2001, Joris Robijn ++ * 2001, Rene Wagner ++ * 2002, Mike Patnode ++ * 2002, Guillaume Filion ++ * 2003, Benjamin Tse (Win32 support) ++ * 2005, Peter Marschall (cleanup) ++ * ++ * Contains main(), plus signal callback functions and a help screen. ++ * ++ * Program init, command-line handling, and the main loop are ++ * implemented here. Also, minimal data about the program such as ++ * the revision number. ++ * ++ * Some of this stuff should probably be move elsewhere eventually, ++ * such as command-line handling and the main loop. main() is supposed ++ * to be "dumb". ++ * ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#ifndef WIN32 ++# include ++# include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "getopt.h" ++ ++#ifdef HAVE_SYS_TIME_H ++# include ++#endif ++/* TODO: fill in what to include otherwise */ ++ ++/* REVISIT: externs should be provided by a header */ ++extern char *optarg; ++extern int optind, optopt, opterr; ++ ++#include "shared/report.h" ++ ++#include "drivers.h" ++#include "sock.h" ++#include "clients.h" ++#include "screenlist.h" ++#include "screen.h" ++#include "parse.h" ++#include "render.h" ++#include "serverscreens.h" ++#include "menuscreens.h" ++#include "input.h" ++#include "shared/configfile.h" ++#include "drivers.h" ++#include "main.h" ++ ++ ++#define DEFAULT_BIND_ADDR "127.0.0.1" ++#define DEFAULT_BIND_PORT LCDPORT ++#define DEFAULT_CONFIGFILE "/etc/LCDd.conf" ++#define DEFAULT_USER "nobody" ++#define DEFAULT_DRIVER "curses" ++#define DEFAULT_DRIVER_PATH "" /* not needed */ ++#define MAX_DRIVERS 8 ++#define DEFAULT_FOREGROUND_MODE 0 ++#define DEFAULT_ROTATE_SERVER_SCREEN 1 ++#define DEFAULT_REPORTDEST RPT_DEST_STDERR ++#define DEFAULT_REPORTLEVEL RPT_WARNING ++ ++#define DEFAULT_SCREEN_DURATION 32 ++#define DEFAULT_HEARTBEAT HEARTBEAT_ON ++ ++/* All variables are set to 'unset' values*/ ++#define UNSET_INT -1 ++#define UNSET_STR "\01" ++ ++/* Socket to bind to... ++ ++ Using loopback is much more secure; it means that this port is ++ accessible only to programs running locally on the same host as LCDd. ++ ++ Using variables for these means that (later) we can select which port ++ and which address to bind to at run time. */ ++ ++ ++/* Store some standard defines into vars... */ ++char *version = VERSION; ++char *protocol_version = PROTOCOL_VERSION; ++char *api_version = API_VERSION; ++char *build_date = __DATE__; ++ ++ ++/**** Configuration variables ****/ ++/* Some variables are settable on the command line. This are variables that ++ * change the mode of operation. This includes settings that you can use to ++ * enable debugging: driver selection, report settings, bind address etc. ++ * These variables should be in main.h and main.c (below). ++ * ++ * All other settings do not need to be settable from the command line. They ++ * also do not necesarily need to be read in main.c but can better be read in ++ * in the file concerned. ++ */ ++ ++unsigned int bind_port = UNSET_INT; ++char bind_addr[64]; /* Do not preinit these strings as they will occupy */ ++char configfile[256]; /* a lot of space in the executable. */ ++char user[64]; /* The values will be overwritten anyway... */ ++ ++/* The drivers and their driver parameters */ ++char *drivernames[MAX_DRIVERS]; ++int num_drivers = 0; ++ ++/* End of configuration variables */ ++ ++/* Local variables */ ++static int foreground_mode = UNSET_INT; ++static int report_dest = UNSET_INT; ++static int report_level = UNSET_INT; ++ ++static int stored_argc; ++static char **stored_argv; ++static volatile short got_reload_signal = 0; ++ ++/* Local exported variables */ ++long int timer = 0; ++ ++/**** Local functions ****/ ++static void clear_settings(void); ++static int process_command_line(int argc, char **argv); ++static int process_configfile(char *cfgfile); ++static void set_default_settings(void); ++static void install_signal_handlers(int allow_reload); ++static void child_ok_func(int signal); ++static pid_t daemonize(void); ++static int wave_to_parent(pid_t parent_pid); ++static int init_drivers(void); ++static int drop_privs(char *user); ++static int init_screens(void); ++static void do_reload(void); ++static void do_mainloop(void); ++static void exit_program(int val); ++static void catch_reload_signal(int val); ++static int interpret_boolean_arg(char *s); ++static void output_help_screen(void); ++static void output_GPL_notice(void); ++ ++#define CHAIN(e,f) { if( e>=0 ) { e=(f); }} ++#define CHAIN_END(e,msg) { if( e<0 ) { report( RPT_CRIT,(msg)); exit(e); }} ++ ++ ++int ++main(int argc, char **argv) ++{ ++ int e = 0; ++ pid_t parent_pid = 0; ++ ++ stored_argc = argc; ++ stored_argv = argv; ++ ++ /* ++ * Settings in order of preference: ++ * ++ * 1: Settings specified in command line options... ++ * 2: Settings specified in configuration file... ++ * 3: Default settings ++ * ++ * Because of this, and because one option (-c) specifies where ++ * the configuration file is, things are done in this order: ++ * ++ * 1. Read and set options. ++ * 2. Read configuration file; if option is read in configuration ++ * file and not already set, then set it. ++ * 3. Having read configuration file, if parameter is not set, ++ * set it to the default value. ++ * ++ * It is for this reason that the default values are **NOT** set ++ * in the variable declaration... ++ */ ++ ++ /* Report that server is starting (report will be delayed) */ ++ report(RPT_NOTICE, "LCDd version %s starting", version ); ++ report(RPT_INFO, "Built on %s, protocol version %s, API version %s", ++ build_date, protocol_version, api_version ); ++ ++ clear_settings(); ++ ++ /* Read command line*/ ++ CHAIN( e, process_command_line(argc, argv) ); ++ ++ /* Read config file ++ * If config file was not given on command line use default */ ++ if (strcmp(configfile, UNSET_STR)==0) ++ strncpy(configfile, DEFAULT_CONFIGFILE, sizeof(configfile)); ++ CHAIN( e, process_configfile(configfile) ); ++ ++ /* Set default values*/ ++ set_default_settings(); ++ ++ /* Set reporting settings (will also flush delayed reports) */ ++ set_reporting("LCDd", report_level, report_dest); ++ report(RPT_INFO, "Set report level to %d, output to %s", report_level, ++ ((report_dest == RPT_DEST_SYSLOG) ? "syslog" : "stderr")); ++ CHAIN_END( e, "Critical error while processing settings, abort." ); ++ ++ /* Now, go into daemon mode (if we should)... ++ * We wait for the child to report it is running OK. This mechanism ++ * is used because forking after starting the drivers causes the ++ * child to loose the (LPT) port access. */ ++ if (!foreground_mode) { ++ report(RPT_INFO, "Server forking to background"); ++ CHAIN( e, parent_pid = daemonize() ); ++ } else { ++ output_GPL_notice(); ++ report(RPT_INFO, "Server running in foreground"); ++ } ++ install_signal_handlers (!foreground_mode); ++ /* Only catch SIGHUP if not in foreground mode */ ++ ++ /* Startup the subparts of the server */ ++ CHAIN( e, sock_init(bind_addr, bind_port) ); ++ CHAIN( e, screenlist_init() ); ++ CHAIN( e, init_drivers() ); ++ CHAIN( e, clients_init() ); ++ CHAIN( e, input_init() ); ++ CHAIN( e, menuscreens_init() ); ++ CHAIN( e, server_screen_init() ); ++ CHAIN_END( e, "Critical error while initializing, abort." ); ++ if (!foreground_mode) { ++ /* Tell to parent that startup went OK. */ ++ wave_to_parent (parent_pid); ++ } ++ drop_privs(user); /* This can't be done before, because sending a ++ signal to a process of a different user will fail */ ++ ++ do_mainloop(); ++ /* This loop never stops; we'll get out only with a signal...*/ ++ ++ return 0; ++} ++ ++ ++static void ++clear_settings(void) ++{ ++ int i; ++ ++ debug( RPT_DEBUG, "%s()", __FUNCTION__ ); ++ ++ bind_port = UNSET_INT; ++ strncpy( bind_addr, UNSET_STR, sizeof(bind_addr) ); ++ strncpy( configfile, UNSET_STR, sizeof(configfile) ); ++ strncpy( user, UNSET_STR, sizeof(user) ); ++ foreground_mode = UNSET_INT; ++ rotate_server_screen = UNSET_INT; ++ backlight = UNSET_INT; ++ ++ default_duration = UNSET_INT; ++ report_dest = UNSET_INT; ++ report_level = UNSET_INT; ++ ++ for( i=0; i < num_drivers; i++ ) { ++ free( drivernames[i] ); ++ drivernames[i] = NULL; ++ } ++ num_drivers = 0; ++} ++ ++ ++/* parses arguments given on command line */ ++static int ++process_command_line(int argc, char **argv) ++{ ++ int c, b; ++ int e = 0, help = 0; ++ ++ debug( RPT_DEBUG, "%s( argc=%d, argv=...)", __FUNCTION__, argc ); ++ ++ /* Reset getopt */ ++ opterr = 0; /* Prevent some messages to stderr */ ++ ++ /* Analyze options here.. (please try to keep list of options the ++ * same everywhere) */ ++ while ((c = getopt(argc, argv, "hc:d:f:a:p:u:w:s:r:i:" )) > 0) { ++ switch(c) { ++ case 'h': ++ help = 1; /* Continue to process the other ++ * options */ ++ break; ++ case 'c': ++ strncpy(configfile, optarg, sizeof(configfile)); ++ configfile[sizeof(configfile)-1] = 0; /* Terminate string */ ++ break; ++ case 'd': ++ /* Add to a list of drivers to be initialized later...*/ ++ if (num_drivers < MAX_DRIVERS) { ++ drivernames[num_drivers] = malloc( strlen(optarg)+1 ); ++ strcpy( drivernames[num_drivers], optarg ); ++ num_drivers ++; ++ } else { ++ report( RPT_ERR, "Too many drivers!" ); ++ e = -1; ++ } ++ break; ++ case 'f': ++ b = interpret_boolean_arg( optarg ); ++ if( b == -1 ) { ++ report( RPT_ERR, "Not a boolean value: '%s'", optarg ); ++ e = -1; ++ } else { ++ foreground_mode = b; ++ } ++ break; ++ case 'a': ++ strncpy(bind_addr, optarg, sizeof(bind_addr)); ++ bind_addr[sizeof(bind_addr)-1] = 0; /* Terminate string */ ++ break; ++ case 'p': ++ bind_port = atoi(optarg); ++ break; ++ case 'u': ++ strncpy(user, optarg, sizeof(user)); ++ user[sizeof(user)-1] = 0; /* Terminate string */ ++ break; ++ case 'w': ++ default_duration = (int) (atof(optarg) * 1e6 / TIME_UNIT); ++ if ( default_duration * TIME_UNIT < 2e6 ) { ++ report( RPT_ERR, "Waittime should be at least 2 (seconds), not %.8s", optarg ); ++ e = -1; ++ } ++ break; ++ case 's': ++ b = interpret_boolean_arg( optarg ); ++ if( b == -1 ) { ++ report( RPT_ERR, "Not a boolean value: '%s'", optarg ); ++ e = -1; ++ } else { ++ report_dest = (b) ? RPT_DEST_SYSLOG : RPT_DEST_STDERR; ++ } ++ break; ++ case 'r': ++ report_level = atoi(optarg); ++ break; ++ case 'i': ++ b = interpret_boolean_arg( optarg ); ++ if( b == -1 ) { ++ report( RPT_ERR, "Not a boolean value: '%s'", optarg ); ++ e = -1; ++ } else { ++ rotate_server_screen = b; ++ } ++ break; ++ case '?': ++ /* For some reason getopt also returns an '?' ++ * when an option argument is mission... */ ++ report( RPT_ERR, "Unknown option: '%c'", optopt ); ++ e = -1; ++ break; ++ case ':': ++ report( RPT_ERR, "Missing option argument!" ); ++ e = -1; ++ break; ++ } ++ } ++ ++ if (optind < argc) { ++ report( RPT_ERR, "Non-option arguments on the command line !"); ++ e = -1; ++ } ++ if( help ) { ++ output_help_screen(); ++ e = -1; ++ } ++ return e; ++} ++ ++ ++/* reads and parses configuration file */ ++static int ++process_configfile(char *configfile) ++{ ++ char * s; ++ /*char buf[64];*/ ++ ++ debug( RPT_DEBUG, "%s()", __FUNCTION__ ); ++ ++ /* Read server settings*/ ++ ++ if( config_read_file( configfile ) != 0 ) { ++ report( RPT_CRIT, "Could not read config file: %s", configfile ); ++ return -1; ++ } ++ ++ if( bind_port == UNSET_INT ) ++ bind_port = config_get_int( "server", "port", 0, UNSET_INT ); ++ ++ if( strcmp( bind_addr, UNSET_STR ) == 0 ) ++ strncpy( bind_addr, config_get_string( "server", "bind", 0, UNSET_STR ), sizeof(bind_addr)); ++ ++ if( strcmp( user, UNSET_STR ) == 0 ) ++ strncpy( user, config_get_string( "server", "user", 0, UNSET_STR ), sizeof(user)); ++ ++ if( default_duration == UNSET_INT ) { ++ default_duration = (config_get_float( "server", "waittime", 0, 0 ) * 1e6 / TIME_UNIT ); ++ if( default_duration == 0 ) ++ default_duration = UNSET_INT; ++ else if( default_duration * TIME_UNIT < 2e6 ) { ++ report( RPT_WARNING, "Waittime should be at least 2 (seconds). Set to 2 seconds." ); ++ default_duration = 2e6 / TIME_UNIT; ++ } ++ } ++ ++ if( foreground_mode == UNSET_INT ) { ++ int fg = config_get_bool( "server", "foreground", 0, UNSET_INT ); ++ ++ if( fg != UNSET_INT ) ++ foreground_mode = fg; ++ } ++ ++ if( rotate_server_screen == UNSET_INT ) { ++ rotate_server_screen = config_get_bool( "server", "serverscreen", 0, UNSET_INT ); ++ } ++ ++ if( backlight == UNSET_INT ) { ++ s = config_get_string( "server", "backlight", 0, UNSET_STR ); ++ if( strcmp( s, "on" ) == 0 ) { ++ backlight = BACKLIGHT_ON; ++ } ++ else if( strcmp( s, "off" ) == 0 ) { ++ backlight = BACKLIGHT_OFF; ++ } ++ else if( strcmp( s, "open" ) == 0 ) { ++ backlight = BACKLIGHT_OPEN; ++ } ++ else if( strcmp( s, UNSET_STR ) != 0 ) { ++ report( RPT_WARNING, "Backlight state should be on, off or open" ); ++ } ++ } ++ ++ if (report_dest == UNSET_INT) { ++ int rs = config_get_bool("server", "reportToSyslog", 0, UNSET_INT); ++ ++ if (rs != UNSET_INT) ++ report_dest = (rs) ? RPT_DEST_SYSLOG : RPT_DEST_STDERR; ++ } ++ if( report_level == UNSET_INT ) { ++ report_level = config_get_int( "server", "reportLevel", 0, UNSET_INT ); ++ } ++ ++ ++ /* Read drivers*/ ++ ++ /* If drivers have been specified on the command line, then do not ++ * use the driver list from the config file. ++ */ ++ if( num_drivers == 0 ) { ++ /* read the drivernames*/ ++ ++ while( 1 ) { ++ s = config_get_string( "server", "driver", num_drivers, NULL ); ++ if( !s ) ++ break; ++ if( s[0] != 0 ) { ++ drivernames[num_drivers] = malloc(strlen(s)+1); ++ strcpy( drivernames[num_drivers], s ); ++ num_drivers++; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++ ++static void ++set_default_settings(void) ++{ ++ debug( RPT_DEBUG, "%s()", __FUNCTION__ ); ++ ++ /* Set defaults into unfilled variables....*/ ++ ++ if (bind_port == UNSET_INT) ++ bind_port = DEFAULT_BIND_PORT; ++ if (strcmp( bind_addr, UNSET_STR ) == 0) ++ strncpy (bind_addr, DEFAULT_BIND_ADDR, sizeof(bind_addr)); ++ if (strcmp( user, UNSET_STR ) == 0) ++ strncpy(user, DEFAULT_USER, sizeof(user)); ++ ++ if (foreground_mode == UNSET_INT) ++ foreground_mode = DEFAULT_FOREGROUND_MODE; ++ if (rotate_server_screen == UNSET_INT) ++ rotate_server_screen = DEFAULT_ROTATE_SERVER_SCREEN; ++ ++ if (default_duration == UNSET_INT) ++ default_duration = DEFAULT_SCREEN_DURATION; ++ if (backlight == UNSET_INT) ++ backlight = BACKLIGHT_OPEN; ++ ++ if (report_dest == UNSET_INT ) ++ report_dest = DEFAULT_REPORTDEST; ++ if( report_level == UNSET_INT ) ++ report_level = DEFAULT_REPORTLEVEL; ++ ++ ++ /* Use default driver*/ ++ if( num_drivers == 0 ) { ++ drivernames[0] = malloc(strlen(DEFAULT_DRIVER)+1); ++ strcpy(drivernames[0], DEFAULT_DRIVER); ++ num_drivers = 1; ++ } ++} ++ ++ ++static void ++install_signal_handlers(int allow_reload) ++{ ++#ifndef WIN32 ++ /* Installs signal handlers so that the program does clean exit and ++ * can also receive a reload signal. ++ * sigaction() is favoured over signal() */ ++ ++ struct sigaction sa; ++ ++ debug( RPT_DEBUG, "%s( allow_reload=%d )", __FUNCTION__, allow_reload ); ++ ++ sa.sa_handler = exit_program; ++ sigemptyset ( &(sa.sa_mask) ); ++ sa.sa_flags = SA_RESTART; ++ ++ sigaction (SIGINT, &sa, NULL); /* Ctrl-C will cause a clean exit...*/ ++ sigaction (SIGTERM, &sa, NULL); /* and "kill"...*/ ++ ++ if (allow_reload) { ++ sa.sa_handler = catch_reload_signal; ++ /* On SIGHUP reread config and restart the drivers ! */ ++ } ++ else { ++ /* Treat this signal just like INT and TERM */ ++ } ++ sigaction (SIGHUP, &sa, NULL); ++#else ++ /* Win32 does not support POSIX signals i.e. sigaction(). However, it does ++ * support ANSI signals in mingw. */ ++ signal (SIGINT, exit_program); /* Ctrl-C will cause a clean exit...*/ ++ signal (SIGTERM, exit_program); /* and "kill"...*/ ++ ++ /* REVISIT: implement SIGHUP on windows */ ++#endif ++} ++ ++ ++static void ++child_ok_func(int signal) ++{ ++ /* We only catch this signal to be sure the child runs OK. */ ++ ++ debug( RPT_INFO, "%s( signal=%d )", __FUNCTION__, signal ); ++ ++ /* Exit now ! because of bug? in wait() */ ++ _exit( 0 ); /* Parent exits normally. */ ++} ++ ++ ++static pid_t ++daemonize(void) ++{ ++#ifdef WIN32 ++ /* WIN32 does not support fork() - CreateProcess() does not even have ++ * similar functionality. Instead don't daemonize on WIN32. ++ */ ++ pid_t parent; ++ parent = getpid(); ++#else ++ pid_t child; ++ pid_t parent; ++ int child_status; ++ struct sigaction sa; ++ ++ debug( RPT_DEBUG, "%s()", __FUNCTION__ ); ++ ++ parent = getpid(); ++ debug( RPT_INFO, "parent = %d", parent ); ++ ++ /* Install handler at parent for child's signal */ ++ /* sigaction should be more portable than signal, but it does not ++ * work for some reason. */ ++ sa.sa_handler = child_ok_func; ++ sigemptyset ( &(sa.sa_mask) ); ++ sa.sa_flags = SA_RESTART; ++ sigaction (SIGUSR1, &sa, NULL); ++ ++ /* Do the fork */ ++ switch ((child = fork ()) ) { ++ case -1: ++ report( RPT_ERR, "Could not fork" ); ++ return -1; ++ case 0: /* We are the child */ ++ break; ++ default: /* We are the parent */ ++ debug( RPT_INFO, "child = %d", child ); ++ wait( &child_status ); ++ /* BUG? According to the man page wait() should also return ++ * when a signal comes in that is caught. Instead it ++ * continues to wait. */ ++ ++ if( WIFEXITED(child_status) ) { ++ /* Child exited normally, probably because of some ++ * error. */ ++ debug( RPT_INFO, "Child has terminated!" ); ++ exit( WEXITSTATUS(child_status) ); ++ /* Parent exits with same status as child did... */ ++ } ++ /* Child is still running and has signalled it's OK. ++ * This means the parent can now rest in peace. */ ++ debug( RPT_INFO, "Got OK signal from child." ); ++ exit( 0 ); /* Parent exits normally. */ ++ } ++ /* At this point we are always the child. */ ++ /* Reset signal handler */ ++ sa.sa_handler = SIG_DFL; ++ sigaction (SIGUSR1, &sa, NULL); ++ ++ setsid(); /* Create a new session because otherwise we'll ++ * catch a SIGHUP when the shell is closed. */ ++#endif ++ ++ return parent; ++} ++ ++ ++static int ++wave_to_parent(pid_t parent_pid) ++{ ++#ifndef WIN32 ++ debug( RPT_DEBUG, "%s( parent_pid=%d )", __FUNCTION__, parent_pid ); ++ ++ kill( parent_pid, SIGUSR1 ); ++#endif ++ ++ return 0; ++} ++ ++ ++static int ++init_drivers(void) ++{ ++ int i, res; ++ ++ int output_loaded = 0; ++ ++ debug( RPT_DEBUG, "%s()", __FUNCTION__ ); ++ ++ for (i = 0; i < num_drivers; i++) { ++ ++ res = drivers_load_driver (drivernames[i]); ++ if (res >= 0) { ++ /* Load went OK */ ++ ++ switch( res ) { ++ case 0: /* Driver does input only */ ++ break; ++ case 1: /* Driver does output */ ++ output_loaded = 1; ++ break; ++ case 2: /* Driver does output in foreground (don't daemonize) */ ++ foreground_mode = 1; ++ output_loaded = 1; ++ break; ++ } ++ } else { ++ report( RPT_ERR, "Could not load driver %.40s", drivernames[i] ); ++ } ++ } ++ ++ /* Do we have a running output driver ?*/ ++ if ( output_loaded ) { ++ return 0; ++ } else { ++ report( RPT_ERR, "There is no output driver" ); ++ return -1; ++ } ++} ++ ++ ++static int ++drop_privs(char *user) ++{ ++#ifndef WIN32 ++ struct passwd *pwent; ++ ++ debug( RPT_DEBUG, "%s( user=\"%.40s\" )", __FUNCTION__, user ); ++ ++ if (getuid() == 0 || geteuid() == 0) { ++ if ((pwent = getpwnam(user)) == NULL) { ++ report( RPT_ERR, "User %.40s not a valid user!", user ); ++ return -1; ++ } else { ++ if (setuid(pwent->pw_uid) < 0) { ++ report( RPT_ERR, "Unable to switch to user %.40s", user ); ++ return -1; ++ } ++ } ++ } ++#else ++ /* Don't alter privileges in WIN32 */ ++#endif ++ ++ return 0; ++} ++ ++ ++static int ++init_screens(void) ++{ ++ debug( RPT_DEBUG, "%s()", __FUNCTION__ ); ++ ++ if (screenlist_init () < 0) { ++ report(RPT_ERR, "Error initializing screen list"); ++ return -1; ++ } ++ ++ /* Add the server screen */ ++ if (server_screen_init () < 0) { ++ report(RPT_ERR, "Error initializing server screens"); ++ return -1; ++ } ++ if (!rotate_server_screen) { ++ /* Display the server screen only when there are no other ++ * screens */ ++ /* server_screen->priority = PRI_BACKGROUND; */ ++ } ++ return 0; ++} ++ ++ ++static void ++do_reload(void) ++{ ++ int e = 0; ++ ++ drivers_unload_all (); /* Close all drivers */ ++ ++ config_clear(); ++ clear_settings(); ++ ++ /* Reread command line*/ ++ CHAIN( e, process_command_line (stored_argc, stored_argv) ); ++ ++ /* Reread config file */ ++ if (strcmp(configfile, UNSET_STR)==0) ++ strncpy(configfile, DEFAULT_CONFIGFILE, sizeof(configfile)); ++ CHAIN( e, process_configfile (configfile) ); ++ ++ /* Set default values */ ++ CHAIN( e, ( set_default_settings(), 0 )); ++ ++ /* Set reporting values */ ++ CHAIN( e, set_reporting("LCDd", report_level, report_dest) ); ++ CHAIN( e, ( report(RPT_INFO, "Set report level to %d, output to %s", report_level, ++ ((report_dest == RPT_DEST_SYSLOG) ? "syslog" : "stderr")), 0 ) ); ++ ++ /* And restart the drivers */ ++ CHAIN( e, init_drivers() ); ++ CHAIN_END( e, "Critical error while reloading, abort." ); ++} ++ ++ ++static void ++do_mainloop(void) ++{ ++ Screen * s; ++#ifndef WIN32 ++ struct timeval t; ++ struct timeval last_t; ++#else ++ LARGE_INTEGER t; ++ LARGE_INTEGER last_t; ++ LARGE_INTEGER perf_freq; /* frequency of high perf counter (cycles per usec) */ ++#endif ++ int sleeptime; ++ long int process_lag = 0; ++ long int render_lag = 0; ++ long int t_diff; ++ ++ debug( RPT_DEBUG, "%s()", __FUNCTION__ ); ++ ++#ifndef WIN32 ++ gettimeofday (&t, NULL); /* Get initial time */ ++#else ++ QueryPerformanceFrequency(&perf_freq); ++ /* scale perf_freq to number of cycles per micro-sec */ ++ /* REVISIT: this causes rounding errors below but is more efficient */ ++ perf_freq.QuadPart /= 1e6; ++ QueryPerformanceCounter(&t); ++#endif ++ ++ while (1) { ++ /* Get current time */ ++ last_t = t; ++#ifndef WIN32 ++ gettimeofday (&t, NULL); ++ t_diff = ((t.tv_sec - last_t.tv_sec) * 1e6 + (t.tv_usec - last_t.tv_usec)); ++#else ++ QueryPerformanceCounter(&t); ++ /*t_diff.HighPart = t.HighPart - last_t.HighPart; ++ t_diff.LowPart = t.LowPart - last_t.LowPart; ++ */ ++ t_diff = t.QuadPart - last_t.QuadPart; ++ t_diff /= perf_freq.QuadPart; /* scale to microseconds */ ++ /* REVISIT: assumes fits into long */ ++#endif ++ process_lag += t_diff; ++ if (process_lag > 0) { ++ /* Time for a processing stroke */ ++ sock_poll_clients (); /* poll clients for input*/ ++ parse_all_client_messages (); /* analyze input from network clients*/ ++ handle_input (); /* handle key input from devices*/ ++ ++ /* We've done the job... */ ++ process_lag = 0 - (1e6/PROCESS_FREQ); ++ /* Note : this does not make a fixed frequency */ ++ } ++ ++ render_lag += t_diff; ++ if (render_lag > 0) { ++ /* Time for a rendering stroke */ ++ timer ++; ++ screenlist_process (); ++ s = screenlist_current (); ++ ++ /* TODO: Move this call to every client connection ++ * and every screen add... ++ */ ++ if( s == server_screen ) { ++ update_server_screen (timer); ++ } ++ render_screen (s, timer); ++ ++ /* We've done the job... */ ++ if( render_lag > (1e6/RENDER_FREQ) * MAX_RENDER_LAG_FRAMES ) { ++ /* Cause rendering slowdown because too much lag */ ++ render_lag = (1e6/RENDER_FREQ) * MAX_RENDER_LAG_FRAMES; ++ } ++ render_lag -= (1e6/RENDER_FREQ); ++ /* Note: this DOES make a fixed frequency (except with slowdown) */ ++ } ++ ++ /* Sleep just as long as needed */ ++ sleeptime = min (0-process_lag, 0-render_lag); ++ if( sleeptime > 0 ) { ++#ifndef WIN32 ++ usleep (sleeptime); ++#else ++ /* Sleep in Windows takes milliseconds argument */ ++ Sleep(sleeptime / 1000); ++#endif ++ } ++ ++ /* Check if a SIGHUP has been caught */ ++ if( got_reload_signal ) { ++ got_reload_signal = 0; ++ do_reload (); ++ } ++ } ++ ++ /* Quit! */ ++ exit_program (0); ++} ++ ++ ++static void ++exit_program(int val) ++{ ++ char buf[64]; ++ ++ debug( RPT_DEBUG, "%s( val=%d )", __FUNCTION__, val ); ++ ++ /* TODO: These things shouldn't be so interdependent. The order ++ * things are shut down in shouldn't matter... ++ */ ++ ++ if( val > 0 ) { ++ strncpy(buf, "Server shutting down on ", sizeof (buf) ); ++ switch(val) { ++ case 1: strcat(buf, "SIGHUP"); break; ++ case 2: strcat(buf, "SIGINT"); break; ++ case 15: strcat(buf, "SIGTERM"); break; ++ default: snprintf(buf, sizeof(buf), "Server shutting down on signal %d", val); break; ++ /* Other values should not be seen, but just in case.. */ ++ } ++ report(RPT_NOTICE, buf); /* report it */ ++ } ++ ++ /* Set emergency reporting and flush all messages if not done already. */ ++ if (report_level == UNSET_INT ) ++ report_level = DEFAULT_REPORTLEVEL; ++ if (report_dest == UNSET_INT ) ++ report_dest = DEFAULT_REPORTDEST; ++ set_reporting("LCDd", report_level, report_dest); ++ ++ goodbye_screen (); /* display goodbye screen on LCD display */ ++ drivers_unload_all (); /* release driver memory and file descriptors */ ++ ++ /* Shutdown things if server start was complete */ ++ clients_shutdown (); /* shutdown clients (must come first) */ ++ menuscreens_shutdown (); ++ screenlist_shutdown (); /* shutdown screens (must come after client_shutdown) */ ++ input_shutdown (); /* shutdown key input part */ ++ sock_shutdown(); /* shutdown the sockets server */ ++ ++ report( RPT_INFO, "Exiting." ); ++ _exit (0); ++} ++ ++ ++static void ++catch_reload_signal(int val) ++{ ++ debug( RPT_DEBUG, "%s( val=%d )", __FUNCTION__, val ); ++ ++ got_reload_signal = 1; ++} ++ ++ ++static int ++interpret_boolean_arg(char *s) ++{ ++ if( strcmp( s, "on" ) == 0 || strcmp( s, "yes" ) == 0 ++ || strcmp( s, "true" ) == 0 || strcmp( s, "1" ) == 0 ) { ++ return 1; ++ } ++ if( strcmp( s, "off" ) == 0 || strcmp( s, "no" ) == 0 ++ || strcmp( s, "false" ) == 0 || strcmp( s, "0" ) == 0 ) { ++ return 0; ++ } ++ return -1; ++} ++ ++ ++static void ++output_GPL_notice(void) ++{ ++ /* This will only be invoked when running in foreground ++ * So, directly output to stderr ++ */ ++ fprintf (stderr, "LCDd %s, LCDproc Protocol %s\n", VERSION, PROTOCOL_VERSION); ++ fprintf (stderr, "Part of LCDproc\n"); ++ fprintf (stderr, "Copyright (C) 1998-2003 William Ferrell, Scott Scriven\n"); ++ fprintf (stderr, " and many other contributors\n\n"); ++ fprintf (stderr, "This program is free software; you can redistribute it and/or\n"); ++ fprintf (stderr, "modify it under the terms of the GNU General Public License\n"); ++ fprintf (stderr, "as published by the Free Software Foundation; either version 2\n"); ++ fprintf (stderr, "of the License, or (at your option) any later version.\n\n"); ++ ++ fprintf (stderr, "This program is distributed in the hope that it will be useful,\n"); ++ fprintf (stderr, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); ++ fprintf (stderr, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); ++ fprintf (stderr, "GNU General Public License for more details.\n\n"); ++ ++ fprintf (stderr, "The file COPYING contains the GNU General Public License.\n"); ++ fprintf (stderr, "You should have received a copy of the GNU General Public License\n"); ++ fprintf (stderr, "along with this program; if not, write to the Free Software\n"); ++ fprintf (stderr, "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\n"); ++} ++ ++ ++static void ++output_help_screen(void) ++{ ++ /* Help screen is printed to stdout on purpose. No reason to have ++ * this in syslog... ++ */ ++ debug( RPT_DEBUG, "%s()", __FUNCTION__ ); ++ ++ fprintf (stdout, "LCDd: LCDproc Server Daemon, %s\n", version); ++ fprintf (stdout, "Copyright (c) 1999-2003 Scott Scriven, William Ferrell, and misc contributors\n"); ++ fprintf (stdout, "This program is freely redistributable under the terms of the GNU Public License\n\n"); ++ fprintf (stdout, "Usage: LCDd [ -h ] [ -c ] [ -d ] [ -f ] \\\n"); ++ fprintf (stdout, "\t[-a ] [ -p ] [ -u ] [ -w