From c0b6b199a9878bc1e95907200501211c09c1e66c Mon Sep 17 00:00:00 2001 From: Niklas Goby Date: Wed, 23 Nov 2011 11:56:19 +0100 Subject: created modules --- .gitignore | 1 - common/fbgui.h | 30 - customdhcpcd/src/.gitignore | 5 - customdhcpcd/src/CMakeLists.txt | 17 - customdhcpcd/src/README | 45 - customdhcpcd/src/arp.c | 284 ----- customdhcpcd/src/arp.h | 39 - customdhcpcd/src/client.c | 1149 -------------------- customdhcpcd/src/client.h | 35 - customdhcpcd/src/common.c | 249 ----- customdhcpcd/src/common.h | 68 -- customdhcpcd/src/config.h | 133 --- customdhcpcd/src/configure.c | 814 -------------- customdhcpcd/src/configure.h | 38 - customdhcpcd/src/dhcp.c | 933 ---------------- customdhcpcd/src/dhcp.h | 215 ---- customdhcpcd/src/dhcpcd.c | 671 ------------ customdhcpcd/src/dhcpcd.h | 108 -- customdhcpcd/src/dhcpcd.sh | 46 - customdhcpcd/src/discover.c | 7 - customdhcpcd/src/discover.h | 12 - customdhcpcd/src/duid.c | 118 -- customdhcpcd/src/duid.h | 42 - customdhcpcd/src/info.c | 472 -------- customdhcpcd/src/info.h | 42 - customdhcpcd/src/interface.c | 1060 ------------------ customdhcpcd/src/interface.h | 173 --- customdhcpcd/src/ipv4ll.c | 70 -- customdhcpcd/src/ipv4ll.h | 39 - customdhcpcd/src/logger.c | 154 --- customdhcpcd/src/logger.h | 48 - customdhcpcd/src/logwriter.c | 260 ----- customdhcpcd/src/logwriter.h | 40 - customdhcpcd/src/signal.c | 183 ---- customdhcpcd/src/signal.h | 40 - customdhcpcd/src/socket.c | 647 ----------- customdhcpcd/src/socket.h | 46 - customdhcpcd/src/version.h | 1 - src/common/fbgui.h | 30 + src/customdhcpcd/.gitignore | 5 + src/customdhcpcd/CMakeLists.txt | 17 + src/customdhcpcd/README | 45 + src/customdhcpcd/arp.c | 284 +++++ src/customdhcpcd/arp.h | 39 + src/customdhcpcd/client.c | 1149 ++++++++++++++++++++ src/customdhcpcd/client.h | 35 + src/customdhcpcd/common.c | 249 +++++ src/customdhcpcd/common.h | 68 ++ src/customdhcpcd/config.h | 133 +++ src/customdhcpcd/configure.c | 814 ++++++++++++++ src/customdhcpcd/configure.h | 38 + src/customdhcpcd/dhcp.c | 933 ++++++++++++++++ src/customdhcpcd/dhcp.h | 215 ++++ src/customdhcpcd/dhcpcd.c | 671 ++++++++++++ src/customdhcpcd/dhcpcd.h | 108 ++ src/customdhcpcd/dhcpcd.sh | 46 + src/customdhcpcd/discover.c | 7 + src/customdhcpcd/discover.h | 12 + src/customdhcpcd/duid.c | 118 ++ src/customdhcpcd/duid.h | 42 + src/customdhcpcd/info.c | 472 ++++++++ src/customdhcpcd/info.h | 42 + src/customdhcpcd/interface.c | 1060 ++++++++++++++++++ src/customdhcpcd/interface.h | 173 +++ src/customdhcpcd/ipv4ll.c | 70 ++ src/customdhcpcd/ipv4ll.h | 39 + src/customdhcpcd/logger.c | 154 +++ src/customdhcpcd/logger.h | 48 + src/customdhcpcd/logwriter.c | 260 +++++ src/customdhcpcd/logwriter.h | 40 + src/customdhcpcd/signal.c | 183 ++++ src/customdhcpcd/signal.h | 40 + src/customdhcpcd/socket.c | 647 +++++++++++ src/customdhcpcd/socket.h | 46 + src/customdhcpcd/version.h | 1 + src/downloadmanager.cpp | 215 ---- src/downloadmanager.h | 84 -- src/fbgui.cpp | 492 --------- src/fbgui.h | 126 --- src/fbgui.pro | 50 - src/fbgui.qrc | 36 - src/fbgui/downloadmanager.cpp | 215 ++++ src/fbgui/downloadmanager.h | 84 ++ src/fbgui/fbgui.cpp | 492 +++++++++ src/fbgui/fbgui.h | 126 +++ src/fbgui/fbgui.pro | 50 + src/fbgui/fbgui.qrc | 36 + src/fbgui/html/background.png | Bin 0 -> 364392 bytes src/fbgui/html/continueBoot.html | 24 + .../ui-bg_diagonals-thick_18_b81900_40x40.png | Bin 0 -> 260 bytes .../ui-bg_diagonals-thick_20_666666_40x40.png | Bin 0 -> 251 bytes .../css/images/ui-bg_flat_10_000000_40x100.png | Bin 0 -> 178 bytes .../css/images/ui-bg_glass_100_f6f6f6_1x400.png | Bin 0 -> 104 bytes .../css/images/ui-bg_glass_100_fdf5ce_1x400.png | Bin 0 -> 125 bytes .../css/images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../images/ui-bg_gloss-wave_35_f6a828_500x100.png | Bin 0 -> 3762 bytes .../ui-bg_highlight-soft_100_eeeeee_1x100.png | Bin 0 -> 90 bytes .../ui-bg_highlight-soft_75_ffe45c_1x100.png | Bin 0 -> 129 bytes .../html/css/images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../html/css/images/ui-icons_228ef1_256x240.png | Bin 0 -> 4369 bytes .../html/css/images/ui-icons_ef8c08_256x240.png | Bin 0 -> 4369 bytes .../html/css/images/ui-icons_ffd27a_256x240.png | Bin 0 -> 4369 bytes .../html/css/images/ui-icons_ffffff_256x240.png | Bin 0 -> 4369 bytes src/fbgui/html/css/jquery-ui-1.8.16.css | 568 ++++++++++ src/fbgui/html/images/loading.gif | Bin 0 -> 8787 bytes src/fbgui/html/js/jquery-1.6.4.min.js | 4 + src/fbgui/html/js/jquery-ui-1.8.16.min.js | 791 ++++++++++++++ src/fbgui/html/js/networkDiscovery.js | 278 +++++ src/fbgui/html/loadsystem.css | 90 ++ src/fbgui/html/loadsystem.html | 35 + src/fbgui/html/networkdiscovery.css | 90 ++ src/fbgui/html/networkdiscovery.html | 89 ++ src/fbgui/html/networkdiscovery_debug.html | 88 ++ src/fbgui/html/networkdiscovery_userchoice.html | 33 + .../html/networkdiscovery_userchoice_debug.html | 33 + src/fbgui/html/old.png | Bin 0 -> 316905 bytes src/fbgui/html/preload-debug.html | 34 + src/fbgui/html/preload.css | 105 ++ src/fbgui/html/preload.html | 42 + src/fbgui/interfaceconfiguration.cpp | 140 +++ src/fbgui/interfaceconfiguration.h | 66 ++ src/fbgui/javascriptinterface.cpp | 235 ++++ src/fbgui/javascriptinterface.h | 72 ++ src/fbgui/loggerengine.cpp | 116 ++ src/fbgui/loggerengine.h | 69 ++ src/fbgui/main.cpp | 268 +++++ src/fbgui/ndgui.cpp | 588 ++++++++++ src/fbgui/ndgui.h | 115 ++ src/fbgui/networkdiscovery.cpp | 990 +++++++++++++++++ src/fbgui/networkdiscovery.h | 139 +++ src/fbgui/networkmanager.cpp | 681 ++++++++++++ src/fbgui/networkmanager.h | 73 ++ src/fbgui/sysinfo.cpp | 180 +++ src/fbgui/sysinfo.h | 50 + src/html/background.png | Bin 364392 -> 0 bytes src/html/continueBoot.html | 24 - .../ui-bg_diagonals-thick_18_b81900_40x40.png | Bin 260 -> 0 bytes .../ui-bg_diagonals-thick_20_666666_40x40.png | Bin 251 -> 0 bytes .../css/images/ui-bg_flat_10_000000_40x100.png | Bin 178 -> 0 bytes .../css/images/ui-bg_glass_100_f6f6f6_1x400.png | Bin 104 -> 0 bytes .../css/images/ui-bg_glass_100_fdf5ce_1x400.png | Bin 125 -> 0 bytes .../css/images/ui-bg_glass_65_ffffff_1x400.png | Bin 105 -> 0 bytes .../images/ui-bg_gloss-wave_35_f6a828_500x100.png | Bin 3762 -> 0 bytes .../ui-bg_highlight-soft_100_eeeeee_1x100.png | Bin 90 -> 0 bytes .../ui-bg_highlight-soft_75_ffe45c_1x100.png | Bin 129 -> 0 bytes src/html/css/images/ui-icons_222222_256x240.png | Bin 4369 -> 0 bytes src/html/css/images/ui-icons_228ef1_256x240.png | Bin 4369 -> 0 bytes src/html/css/images/ui-icons_ef8c08_256x240.png | Bin 4369 -> 0 bytes src/html/css/images/ui-icons_ffd27a_256x240.png | Bin 4369 -> 0 bytes src/html/css/images/ui-icons_ffffff_256x240.png | Bin 4369 -> 0 bytes src/html/css/jquery-ui-1.8.16.css | 568 ---------- src/html/images/loading.gif | Bin 8787 -> 0 bytes src/html/js/jquery-1.6.4.min.js | 4 - src/html/js/jquery-ui-1.8.16.min.js | 791 -------------- src/html/js/networkDiscovery.js | 278 ----- src/html/loadsystem.css | 90 -- src/html/loadsystem.html | 35 - src/html/networkdiscovery.css | 90 -- src/html/networkdiscovery.html | 89 -- src/html/networkdiscovery_debug.html | 88 -- src/html/networkdiscovery_userchoice.html | 33 - src/html/networkdiscovery_userchoice_debug.html | 33 - src/html/old.png | Bin 316905 -> 0 bytes src/html/preload-debug.html | 34 - src/html/preload.css | 105 -- src/html/preload.html | 42 - src/interfaceconfiguration.cpp | 140 --- src/interfaceconfiguration.h | 66 -- src/javascriptinterface.cpp | 235 ---- src/javascriptinterface.h | 72 -- src/loggerengine.cpp | 116 -- src/loggerengine.h | 69 -- src/main.cpp | 268 ----- src/ndgui.cpp | 588 ---------- src/ndgui.h | 115 -- src/networkdiscovery.cpp | 990 ----------------- src/networkdiscovery.h | 139 --- src/networkmanager.cpp | 681 ------------ src/networkmanager.h | 73 -- src/sysinfo.cpp | 180 --- src/sysinfo.h | 50 - 181 files changed, 15422 insertions(+), 15423 deletions(-) delete mode 100644 common/fbgui.h delete mode 100644 customdhcpcd/src/.gitignore delete mode 100644 customdhcpcd/src/CMakeLists.txt delete mode 100644 customdhcpcd/src/README delete mode 100644 customdhcpcd/src/arp.c delete mode 100644 customdhcpcd/src/arp.h delete mode 100644 customdhcpcd/src/client.c delete mode 100644 customdhcpcd/src/client.h delete mode 100644 customdhcpcd/src/common.c delete mode 100644 customdhcpcd/src/common.h delete mode 100644 customdhcpcd/src/config.h delete mode 100644 customdhcpcd/src/configure.c delete mode 100644 customdhcpcd/src/configure.h delete mode 100644 customdhcpcd/src/dhcp.c delete mode 100644 customdhcpcd/src/dhcp.h delete mode 100644 customdhcpcd/src/dhcpcd.c delete mode 100644 customdhcpcd/src/dhcpcd.h delete mode 100644 customdhcpcd/src/dhcpcd.sh delete mode 100644 customdhcpcd/src/discover.c delete mode 100644 customdhcpcd/src/discover.h delete mode 100644 customdhcpcd/src/duid.c delete mode 100644 customdhcpcd/src/duid.h delete mode 100644 customdhcpcd/src/info.c delete mode 100644 customdhcpcd/src/info.h delete mode 100644 customdhcpcd/src/interface.c delete mode 100644 customdhcpcd/src/interface.h delete mode 100644 customdhcpcd/src/ipv4ll.c delete mode 100644 customdhcpcd/src/ipv4ll.h delete mode 100644 customdhcpcd/src/logger.c delete mode 100644 customdhcpcd/src/logger.h delete mode 100644 customdhcpcd/src/logwriter.c delete mode 100644 customdhcpcd/src/logwriter.h delete mode 100644 customdhcpcd/src/signal.c delete mode 100644 customdhcpcd/src/signal.h delete mode 100644 customdhcpcd/src/socket.c delete mode 100644 customdhcpcd/src/socket.h delete mode 100644 customdhcpcd/src/version.h create mode 100644 src/common/fbgui.h create mode 100644 src/customdhcpcd/.gitignore create mode 100644 src/customdhcpcd/CMakeLists.txt create mode 100644 src/customdhcpcd/README create mode 100644 src/customdhcpcd/arp.c create mode 100644 src/customdhcpcd/arp.h create mode 100644 src/customdhcpcd/client.c create mode 100644 src/customdhcpcd/client.h create mode 100644 src/customdhcpcd/common.c create mode 100644 src/customdhcpcd/common.h create mode 100644 src/customdhcpcd/config.h create mode 100644 src/customdhcpcd/configure.c create mode 100644 src/customdhcpcd/configure.h create mode 100644 src/customdhcpcd/dhcp.c create mode 100644 src/customdhcpcd/dhcp.h create mode 100644 src/customdhcpcd/dhcpcd.c create mode 100644 src/customdhcpcd/dhcpcd.h create mode 100644 src/customdhcpcd/dhcpcd.sh create mode 100644 src/customdhcpcd/discover.c create mode 100644 src/customdhcpcd/discover.h create mode 100644 src/customdhcpcd/duid.c create mode 100644 src/customdhcpcd/duid.h create mode 100644 src/customdhcpcd/info.c create mode 100644 src/customdhcpcd/info.h create mode 100644 src/customdhcpcd/interface.c create mode 100644 src/customdhcpcd/interface.h create mode 100644 src/customdhcpcd/ipv4ll.c create mode 100644 src/customdhcpcd/ipv4ll.h create mode 100644 src/customdhcpcd/logger.c create mode 100644 src/customdhcpcd/logger.h create mode 100644 src/customdhcpcd/logwriter.c create mode 100644 src/customdhcpcd/logwriter.h create mode 100644 src/customdhcpcd/signal.c create mode 100644 src/customdhcpcd/signal.h create mode 100644 src/customdhcpcd/socket.c create mode 100644 src/customdhcpcd/socket.h create mode 100644 src/customdhcpcd/version.h delete mode 100644 src/downloadmanager.cpp delete mode 100644 src/downloadmanager.h delete mode 100644 src/fbgui.cpp delete mode 100644 src/fbgui.h delete mode 100644 src/fbgui.pro delete mode 100644 src/fbgui.qrc create mode 100644 src/fbgui/downloadmanager.cpp create mode 100644 src/fbgui/downloadmanager.h create mode 100644 src/fbgui/fbgui.cpp create mode 100644 src/fbgui/fbgui.h create mode 100644 src/fbgui/fbgui.pro create mode 100644 src/fbgui/fbgui.qrc create mode 100644 src/fbgui/html/background.png create mode 100644 src/fbgui/html/continueBoot.html create mode 100644 src/fbgui/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png create mode 100644 src/fbgui/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png create mode 100644 src/fbgui/html/css/images/ui-bg_flat_10_000000_40x100.png create mode 100644 src/fbgui/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png create mode 100644 src/fbgui/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png create mode 100644 src/fbgui/html/css/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 src/fbgui/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png create mode 100644 src/fbgui/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png create mode 100644 src/fbgui/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png create mode 100644 src/fbgui/html/css/images/ui-icons_222222_256x240.png create mode 100644 src/fbgui/html/css/images/ui-icons_228ef1_256x240.png create mode 100644 src/fbgui/html/css/images/ui-icons_ef8c08_256x240.png create mode 100644 src/fbgui/html/css/images/ui-icons_ffd27a_256x240.png create mode 100644 src/fbgui/html/css/images/ui-icons_ffffff_256x240.png create mode 100644 src/fbgui/html/css/jquery-ui-1.8.16.css create mode 100644 src/fbgui/html/images/loading.gif create mode 100644 src/fbgui/html/js/jquery-1.6.4.min.js create mode 100644 src/fbgui/html/js/jquery-ui-1.8.16.min.js create mode 100644 src/fbgui/html/js/networkDiscovery.js create mode 100644 src/fbgui/html/loadsystem.css create mode 100644 src/fbgui/html/loadsystem.html create mode 100644 src/fbgui/html/networkdiscovery.css create mode 100644 src/fbgui/html/networkdiscovery.html create mode 100644 src/fbgui/html/networkdiscovery_debug.html create mode 100644 src/fbgui/html/networkdiscovery_userchoice.html create mode 100644 src/fbgui/html/networkdiscovery_userchoice_debug.html create mode 100644 src/fbgui/html/old.png create mode 100644 src/fbgui/html/preload-debug.html create mode 100644 src/fbgui/html/preload.css create mode 100644 src/fbgui/html/preload.html create mode 100644 src/fbgui/interfaceconfiguration.cpp create mode 100644 src/fbgui/interfaceconfiguration.h create mode 100644 src/fbgui/javascriptinterface.cpp create mode 100644 src/fbgui/javascriptinterface.h create mode 100644 src/fbgui/loggerengine.cpp create mode 100644 src/fbgui/loggerengine.h create mode 100644 src/fbgui/main.cpp create mode 100644 src/fbgui/ndgui.cpp create mode 100644 src/fbgui/ndgui.h create mode 100644 src/fbgui/networkdiscovery.cpp create mode 100644 src/fbgui/networkdiscovery.h create mode 100644 src/fbgui/networkmanager.cpp create mode 100644 src/fbgui/networkmanager.h create mode 100644 src/fbgui/sysinfo.cpp create mode 100644 src/fbgui/sysinfo.h delete mode 100644 src/html/background.png delete mode 100644 src/html/continueBoot.html delete mode 100644 src/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png delete mode 100644 src/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png delete mode 100644 src/html/css/images/ui-bg_flat_10_000000_40x100.png delete mode 100644 src/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png delete mode 100644 src/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png delete mode 100644 src/html/css/images/ui-bg_glass_65_ffffff_1x400.png delete mode 100644 src/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png delete mode 100644 src/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png delete mode 100644 src/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png delete mode 100644 src/html/css/images/ui-icons_222222_256x240.png delete mode 100644 src/html/css/images/ui-icons_228ef1_256x240.png delete mode 100644 src/html/css/images/ui-icons_ef8c08_256x240.png delete mode 100644 src/html/css/images/ui-icons_ffd27a_256x240.png delete mode 100644 src/html/css/images/ui-icons_ffffff_256x240.png delete mode 100644 src/html/css/jquery-ui-1.8.16.css delete mode 100644 src/html/images/loading.gif delete mode 100644 src/html/js/jquery-1.6.4.min.js delete mode 100644 src/html/js/jquery-ui-1.8.16.min.js delete mode 100644 src/html/js/networkDiscovery.js delete mode 100644 src/html/loadsystem.css delete mode 100644 src/html/loadsystem.html delete mode 100644 src/html/networkdiscovery.css delete mode 100644 src/html/networkdiscovery.html delete mode 100644 src/html/networkdiscovery_debug.html delete mode 100644 src/html/networkdiscovery_userchoice.html delete mode 100644 src/html/networkdiscovery_userchoice_debug.html delete mode 100644 src/html/old.png delete mode 100644 src/html/preload-debug.html delete mode 100644 src/html/preload.css delete mode 100644 src/html/preload.html delete mode 100644 src/interfaceconfiguration.cpp delete mode 100644 src/interfaceconfiguration.h delete mode 100644 src/javascriptinterface.cpp delete mode 100644 src/javascriptinterface.h delete mode 100644 src/loggerengine.cpp delete mode 100644 src/loggerengine.h delete mode 100644 src/main.cpp delete mode 100644 src/ndgui.cpp delete mode 100644 src/ndgui.h delete mode 100644 src/networkdiscovery.cpp delete mode 100644 src/networkdiscovery.h delete mode 100644 src/networkmanager.cpp delete mode 100644 src/networkmanager.h delete mode 100644 src/sysinfo.cpp delete mode 100644 src/sysinfo.h diff --git a/.gitignore b/.gitignore index 8d4c380..12331fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -fbgui *.o *~ core *.core moc_*.* diff --git a/common/fbgui.h b/common/fbgui.h deleted file mode 100644 index 9e2c0be..0000000 --- a/common/fbgui.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - */ - - - -#ifndef COMMON_FBGUI_H -#define COMMON_FBGUI_H - -#define DEFAULT_INTERFACE_CONF_LOCATION "/var/tmp/conf_" -#define DEFAULT_QTSOCKETADDRESS "/var/tmp/qt_c_socket_default" -#define DHCP_MESSAGE_SIZE 2048 -#define ACK_SIZE 4 - -#define DHCPCD_EXIT 9 -#define DHCPCD_ARP_TEST 10 -#define DHCPCD_CONFIGURE 11 -#define DHCPCD_WRITE 12 -#define DHCPCD_LOG 13 - -#endif // COMMON_FBGUI_H diff --git a/customdhcpcd/src/.gitignore b/customdhcpcd/src/.gitignore deleted file mode 100644 index e531d2b..0000000 --- a/customdhcpcd/src/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.o -dhcpcd -dhcpcd.8 -dhcpcd-*.bz2 -build diff --git a/customdhcpcd/src/CMakeLists.txt b/customdhcpcd/src/CMakeLists.txt deleted file mode 100644 index a716a5a..0000000 --- a/customdhcpcd/src/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(customdhcpdcd) - -set(CMAKE_C_FLAGS "-lrt") - -set(CUSTOMDHCPCD_SOURCES arp.c configure.c info.c logger.c socket.c client.c discover.c interface.c logwriter.c -common.c dhcp.c duid.c ipv4ll.c signal.c) - -#file(GLOB_RECURSE CUSTOMDHCPCD_SOURCES *.c) -file(GLOB_RECURSE CUSTOMDHCPCD_HEADERS *.h) - -add_library(customdhcpcd SHARED ${CUSTOMDHCPCD_SOURCES} ${CUSTOMDHCPCD_HEADERS}) - -#add_executable(customdhcpcd ${CUSTOMDHCPCD_SOURCES}) -add_executable(cdhcpcd dhcpcd.c) -target_link_libraries(cdhcpcd customdhcpcd ) diff --git a/customdhcpcd/src/README b/customdhcpcd/src/README deleted file mode 100644 index 9089ec6..0000000 --- a/customdhcpcd/src/README +++ /dev/null @@ -1,45 +0,0 @@ -dhcpcd-3 - DHCP client daemon -Copyright 2006-2008 Roy Marples - - -Installation ------------- -Edit config.h to match your building requirements. - -Take special note of ENABLE_DUID and unset it if the target media is -volatile, like say a LiveCD. - -Then just make; make install - -man dhcpcd for command line options - - -Notes ------ -If you're cross compiling you may need to send HAVE_FORK=yes or HAVE_FORK=no -to the make command to avoid to automatic test. - -We try and detect how to restart ntp and ypbind, you can override this with -HAVE_INIT=no or force one of these values -OPENRC (OpenRC as used by Gentoo (forked from baselayout)) -BSDRC (BSD RC system - /etc/rc.d/ntpd restart ) -SERVICE (RedHat service command - service ntpd restart) -SLACKRC (Slackware RC system - /etc/rc.d/rc.ntpd restart) -SYSV (SYSV style - /etc/init.d/ntpd restart) - -You can change the default dir where dhcpcd stores it's .info files with -INFODIR=/var/db - -We now default to using -std=c99. For 64-bit linux, this always works, but -for 32-bit linux it requires either gnu99 or a patch to asm/types.h. -Most distros patch linux headers so this should work fine. -linux-2.6.24 finally ships with a working 32-bit header. -If your linux headers are older, or your distro hasn't patched them you can -set CSTD=gnu99 to work around this. - - -ChangeLog ---------- -We no longer supply a ChangeLog. -However, you're more than welcome to read the git commit comments at -http://git.marples.name/?p=dhcpcd/.git;a=summary diff --git a/customdhcpcd/src/arp.c b/customdhcpcd/src/arp.c deleted file mode 100644 index 794850c..0000000 --- a/customdhcpcd/src/arp.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#ifdef __linux__ -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "common.h" -#include "arp.h" -#include "interface.h" -#include "logger.h" -#include "signal.h" -#include "socket.h" - -/* These are really for IPV4LL */ -#define NPROBES 3 -#define PROBE_INTERVAL 200 -#define NCLAIMS 2 -#define CLAIM_INTERVAL 200 - -/* Linux does not seem to define these handy macros */ -#ifndef ar_sha -#define ar_sha(ap) (((caddr_t) ((ap) + 1)) + 0) -#define ar_spa(ap) (((caddr_t) ((ap) + 1)) + (ap)->ar_hln) -#define ar_tha(ap) (((caddr_t) ((ap) + 1)) + (ap)->ar_hln + (ap)->ar_pln) -#define ar_tpa(ap) (((caddr_t) ((ap) + 1)) + 2 * (ap)->ar_hln + (ap)->ar_pln) -#endif - -#ifndef arphdr_len -#define arphdr_len2(ar_hln, ar_pln) (sizeof (struct arphdr) + \ - 2 * (ar_hln) + 2 * (ar_pln)) -#define arphdr_len(ap) (arphdr_len2 ((ap)->ar_hln, (ap)->ar_pln)) -#endif - -#ifdef ENABLE_ARP - -static int send_arp (const interface_t *iface, int op, struct in_addr sip, - const unsigned char *taddr, struct in_addr tip) -{ - struct arphdr *arp; - size_t arpsize = arphdr_len2 (iface->hwlen, sizeof (sip)); - caddr_t tha; - int retval; - - arp = xzalloc (arpsize); - arp->ar_hrd = htons (iface->family); - arp->ar_pro = htons (ETHERTYPE_IP); - arp->ar_hln = iface->hwlen; - arp->ar_pln = sizeof (sip); - arp->ar_op = htons (op); - memcpy (ar_sha (arp), iface->hwaddr, (size_t) arp->ar_hln); - memcpy (ar_spa (arp), &sip, (size_t) arp->ar_pln); - if (taddr) { - /* NetBSD can return NULL from ar_tha, which is probably wrong - * but we still need to deal with it */ - if (! (tha = ar_tha (arp))) { - free (arp); - errno = EINVAL; - return (-1); - } - memcpy (tha, taddr, (size_t) arp->ar_hln); - } - memcpy (ar_tpa (arp), &tip, (size_t) arp->ar_pln); - - retval = send_packet (iface, ETHERTYPE_ARP, - (unsigned char *) arp, arphdr_len (arp)); - free (arp); - return (retval); -} - -int arp_claim (interface_t *iface, struct in_addr address) -{ - struct arphdr *reply = NULL; - long timeout = 0; - unsigned char *buffer; - int retval = -1; - int nprobes = 0; - int nclaims = 0; - struct in_addr null_address; - struct pollfd fds[] = { - { -1, POLLIN, 0 }, - { -1, POLLIN, 0 } - }; - - if (! iface) - return (-1); - - if (! iface->arpable) { - logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name); - return (0); - } - - if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && - ! IN_LINKLOCAL (ntohl (address.s_addr))) - logger (LOG_INFO, - "checking %s is available on attached networks", - inet_ntoa (address)); - - if (! open_socket (iface, ETHERTYPE_ARP)) - return (-1); - - fds[0].fd = signal_fd (); - fds[1].fd = iface->fd; - - memset (&null_address, 0, sizeof (null_address)); - - buffer = xmalloc (iface->buffer_length); - reply = xmalloc (iface->buffer_length); - - for (;;) { - size_t bufpos = 0; - size_t buflen = iface->buffer_length; - int bytes; - int s = 0; - struct timeval stopat; - struct timeval now; - - /* Only poll if we have a timeout */ - if (timeout > 0) { - s = poll (fds, 2, timeout); - if (s == -1) { - if (errno == EINTR) { - if (signal_exists (NULL) == -1) { - errno = 0; - continue; - } else - break; - } - - logger (LOG_ERR, "poll: `%s'", - strerror (errno)); - break; - } - } - - /* Timed out */ - if (s == 0) { - if (nprobes < NPROBES) { - nprobes ++; - timeout = PROBE_INTERVAL; - logger (LOG_DEBUG, "sending ARP probe #%d", - nprobes); - if (send_arp (iface, ARPOP_REQUEST, - null_address, NULL, - address) == -1) - break; - - /* IEEE1394 cannot set ARP target address - * according to RFC2734 */ - if (nprobes >= NPROBES && - iface->family == ARPHRD_IEEE1394) - nclaims = NCLAIMS; - } else if (nclaims < NCLAIMS) { - nclaims ++; - timeout = CLAIM_INTERVAL; - logger (LOG_DEBUG, "sending ARP claim #%d", - nclaims); - if (send_arp (iface, ARPOP_REQUEST, - address, iface->hwaddr, - address) == -1) - break; - } else { - /* No replies, so done */ - retval = 0; - break; - } - - /* Setup our stop time */ - if (get_time (&stopat) != 0) - break; - stopat.tv_usec += timeout; - - continue; - } - - /* We maybe ARP flooded, so check our time */ - if (get_time (&now) != 0) - break; - if (timercmp (&now, &stopat, >)) { - timeout = 0; - continue; - } - - if (! fds[1].revents & POLLIN) - continue; - - memset (buffer, 0, buflen); - do { - union { - unsigned char *c; - struct in_addr *a; - } rp; - union { - unsigned char *c; - struct ether_addr *a; - } rh; - - memset (reply, 0, iface->buffer_length); - if ((bytes = get_packet (iface, (unsigned char *) reply, - buffer, - &buflen, &bufpos)) == -1) - break; - - /* Only these types are recognised */ - if (reply->ar_op != htons (ARPOP_REPLY)) - continue; - - /* Protocol must be IP. */ - if (reply->ar_pro != htons (ETHERTYPE_IP)) - continue; - if (reply->ar_pln != sizeof (address)) - continue; - if ((unsigned) bytes < sizeof (reply) + - 2 * (4 + reply->ar_hln)) - continue; - - rp.c = (unsigned char *) ar_spa (reply); - rh.c = (unsigned char *) ar_sha (reply); - - /* Ensure the ARP reply is for the our address */ - if (rp.a->s_addr != address.s_addr) - continue; - - /* Some systems send a reply back from our hwaddress, - * which is wierd */ - if (reply->ar_hln == iface->hwlen && - memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0) - continue; - - logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", - inet_ntoa (*rp.a), - hwaddr_ntoa (rh.c, (size_t) reply->ar_hln)); - retval = -1; - goto eexit; - } while (bufpos != 0); - } - -eexit: - close (iface->fd); - iface->fd = -1; - free (buffer); - free (reply); - return (retval); -} -#endif diff --git a/customdhcpcd/src/arp.h b/customdhcpcd/src/arp.h deleted file mode 100644 index 3b7e8ef..0000000 --- a/customdhcpcd/src/arp.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef ARP_H -#define ARP_H - -#ifdef ENABLE_ARP -#include - -#include "interface.h" - -int arp_claim (interface_t *iface, struct in_addr address); -#endif - -#endif diff --git a/customdhcpcd/src/client.c b/customdhcpcd/src/client.c deleted file mode 100644 index b007fd6..0000000 --- a/customdhcpcd/src/client.c +++ /dev/null @@ -1,1149 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#ifdef __linux__ -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "common.h" -#ifdef ENABLE_ARP -# include "arp.h" -#endif -#include "client.h" -#include "configure.h" -#include "dhcp.h" -#include "dhcpcd.h" -#include "info.h" -#include "interface.h" -#ifdef ENABLE_IPV4LL -# include "ipv4ll.h" -#endif -#include "logger.h" -#include "signal.h" -#include "socket.h" - -#include "logwriter.h" - -#ifdef ENABLE_DUID -# include "duid.h" -#endif - -#ifdef ENABLE_INFO -# include "info.h" -#endif - -#ifdef THERE_IS_NO_FORK -# ifndef ENABLE_INFO - # error "Non MMU requires ENABLE_INFO to work" -# endif -#endif - -/* Some platforms don't define INFTIM */ -#ifndef INFTIM -# define INFTIM -1 -#endif - -/* This is out mini timeout. - * Basically we resend the last request every TIMEOUT_MINI seconds. */ -#define TIMEOUT_MINI 3 -/* Except for an infinite timeout. We keep adding TIMEOUT_MINI to - * ourself until TIMEOUT_MINI_INF is reached. */ -#define TIMEOUT_MINI_INF 60 - -#define STATE_INIT 0 -#define STATE_REQUESTING 1 -#define STATE_BOUND 2 -#define STATE_RENEWING 3 -#define STATE_REBINDING 4 -#define STATE_REBOOT 5 -#define STATE_RENEW_REQUESTED 6 -#define STATE_RELEASED 7 - -/* We should define a maximum for the NAK exponential backoff */ -#define NAKOFF_MAX 60 - -#define SOCKET_CLOSED 0 -#define SOCKET_OPEN 1 - -/* Indexes for pollfds */ -#define POLLFD_SIGNAL 0 -#define POLLFD_IFACE 1 - -typedef struct _state { - int *pidfd; - bool forked; - int state; - uint32_t xid; - dhcp_t *dhcp; - int socket; - interface_t *interface; - time_t start; - time_t last_sent; - time_t last_type; - long timeout; - time_t nakoff; - bool daemonised; - bool persistent; - unsigned char *buffer; - size_t buffer_len; - size_t buffer_pos; -} state_t; - -static pid_t daemonise (int *pidfd) -{ - pid_t pid; - sigset_t full; - sigset_t old; -#ifdef THERE_IS_NO_FORK - char **argv; - int i; -#endif - - sigfillset (&full); - sigprocmask (SIG_SETMASK, &full, &old); - -#ifndef THERE_IS_NO_FORK - logger (LOG_DEBUG, "forking to background"); - switch (pid = fork()) { - case -1: - logger (LOG_ERR, "fork: %s", strerror (errno)); - exit (EXIT_FAILURE); - /* NOT REACHED */ - case 0: - setsid (); - close_fds (); - break; - default: - /* Reset our signals as we're the parent about to exit. */ - signal_reset (); - break; - } -#else - logger (LOG_INFO, "forking to background"); - - /* We need to add --daemonise to our options */ - argv = xmalloc (sizeof (char *) * (dhcpcd_argc + 4)); - argv[0] = dhcpcd; - for (i = 1; i < dhcpcd_argc; i++) - argv[i] = dhcpcd_argv[i]; - argv[i] = (char *) "--daemonised"; - if (dhcpcd_skiproutes) { - argv[++i] = (char *) "--skiproutes"; - argv[++i] = dhcpcd_skiproutes; - } - argv[i + 1] = NULL; - - switch (pid = vfork ()) { - case -1: - logger (LOG_ERR, "vfork: %s", strerror (errno)); - _exit (EXIT_FAILURE); - case 0: - signal_reset (); - sigprocmask (SIG_SETMASK, &old, NULL); - execvp (dhcpcd, argv); - logger (LOG_ERR, "execl `%s': %s", dhcpcd, - strerror (errno)); - _exit (EXIT_FAILURE); - } - - free (argv); -#endif - - /* Done with the fd now */ - if (pid != 0) { - writepid (*pidfd, pid); - close (*pidfd); - *pidfd = -1; - - } - - sigprocmask (SIG_SETMASK, &old, NULL); - return (pid); -} - -#ifdef ENABLE_INFO -static bool get_old_lease (state_t *state, const options_t *options) -{ - interface_t *iface = state->interface; - dhcp_t *dhcp = state->dhcp; - struct timeval tv; - unsigned int offset = 0; - - if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) - logger (LOG_INFO, "trying to use old lease in `%s'", - iface->infofile); - if (! read_info (iface, dhcp)) - return (false); - - /* Vitaly important we remove the server information here */ - memset (&dhcp->serveraddress, 0, sizeof (dhcp->serveraddress)); - memset (dhcp->servername, 0, sizeof (dhcp->servername)); - -#ifdef ENABLE_ARP - /* Check that no-one is using the address */ - if ((options->dolastlease || - (IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && - (! options->doipv4ll || - arp_claim (iface, dhcp->address))))) - { - memset (&dhcp->address, 0, sizeof (dhcp->address)); - memset (&dhcp->netmask, 0, sizeof (dhcp->netmask)); - memset (&dhcp->broadcast, 0, sizeof (dhcp->broadcast)); - return (false); - } - - /* Ok, lets use this */ - if (IN_LINKLOCAL (dhcp->address.s_addr)) - return (true); -#endif - - /* Ensure that we can still use the lease */ - if (gettimeofday (&tv, NULL) == -1) { - logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); - return (false); - } - - offset = tv.tv_sec - dhcp->leasedfrom; - if (dhcp->leasedfrom && - tv.tv_sec - dhcp->leasedfrom > dhcp->leasetime) - { - logger (LOG_ERR, "lease expired %u seconds ago", - offset + dhcp->leasetime); - return (false); - } - - if (dhcp->leasedfrom == 0) - offset = 0; - state->timeout = dhcp->renewaltime - offset; - iface->start_uptime = uptime (); - return (true); -} -#endif - -#ifdef THERE_IS_NO_FORK -static void remove_skiproutes (dhcp_t *dhcp, interface_t *iface) -{ - int i = -1; - route_t *route; - route_t *newroute; - - free_route (iface->previous_routes); - iface->previous_routes = NULL; - - NSTAILQ_FOREACH (route, dhcp->routes, entries) { - i++; - - /* Check that we did add this route or not */ - if (dhcpcd_skiproutes) { - char *sk = xstrdup (dhcpcd_skiproutes); - char *skp = sk; - char *token; - bool found = false; - - while ((token = strsep (&skp, ","))) { - if (isdigit (*token) && atoi (token) == i) { - found = true; - break; - } - } - free (sk); - if (found) - continue; - } - - if (! iface->previous_routes) { - iface->previous_routes = xmalloc (sizeof (*iface->previous_routes)); - STAILQ_INIT (iface->previous_routes); - } - - newroute = xmalloc (sizeof (*newroute)); - memcpy (newroute, route, sizeof (*newroute)); - STAILQ_INSERT_TAIL (iface->previous_routes, newroute, entries); - } - - /* We no longer need this argument */ - free (dhcpcd_skiproutes); - dhcpcd_skiproutes = NULL; -} -#endif - -static bool client_setup (state_t *state, const options_t *options) -{ - dhcp_t *dhcp = state->dhcp; - interface_t *iface = state->interface; - - state->state = STATE_INIT; - state->last_type = DHCP_DISCOVER; - state->nakoff = 1; - state->daemonised = options->daemonised; - state->persistent = options->persistent; - - if (options->request_address.s_addr == 0 && - (options->doinform || options->dorequest || options->daemonised)) - { -#ifdef ENABLE_INFO - if (! get_old_lease (state, options)) -#endif - { - free (dhcp); - return (false); - } - state->timeout = 0; - - if (! options->daemonised && - IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) - { - logger (LOG_ERR, "cannot request a link local address"); - return (false); - } -#ifdef THERE_IS_NO_FORK - if (options->daemonised) { - state->state = STATE_BOUND; - state->timeout = dhcp->renewaltime; - iface->previous_address = dhcp->address; - iface->previous_netmask = dhcp->netmask; - remove_skiproutes (dhcp, iface); - } -#endif - - } else { - dhcp->address = options->request_address; - dhcp->netmask = options->request_netmask; - if (dhcp->netmask.s_addr == 0) - dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); - dhcp->broadcast.s_addr = dhcp->address.s_addr | - ~dhcp->netmask.s_addr; - } - - /* Remove all existing addresses. - * After all, we ARE a DHCP client whose job it is to configure the - * interface. We only do this on start, so persistent addresses - * can be added afterwards by the user if needed. */ - if (! options->test && ! options->daemonised) { - if (! options->doinform) { - flush_addresses (iface->name); - } else { - /* The inform address HAS to be configured for it to - * work with most DHCP servers */ - if (options->doinform && - has_address (iface->name, dhcp->address) < 1) - { - add_address (iface->name, dhcp->address, - dhcp->netmask, dhcp->broadcast); - iface->previous_address = dhcp->address; - iface->previous_netmask = dhcp->netmask; - } - } - } - - if (*options->clientid) { - /* Attempt to see if the ClientID is a hardware address */ - iface->clientid_len = hwaddr_aton (NULL, options->clientid); - if (iface->clientid_len) { - iface->clientid = xmalloc (iface->clientid_len); - hwaddr_aton (iface->clientid, options->clientid); - } else { - /* Nope, so mark it as-is */ - iface->clientid_len = strlen (options->clientid) + 1; - iface->clientid = xmalloc (iface->clientid_len); - *iface->clientid = '\0'; - memcpy (iface->clientid + 1, - options->clientid, iface->clientid_len - 1); - } - } else { -#ifdef ENABLE_DUID - unsigned char *duid = NULL; - size_t duid_len = 0; - - if (options->doduid) { - duid = xmalloc (DUID_LEN); - duid_len = get_duid (duid, iface); - } - - if (duid_len > 0) { - logger (LOG_INFO, "DUID = %s", hwaddr_ntoa (duid, duid_len)); - - iface->clientid_len = duid_len + 5; - iface->clientid = xmalloc (iface->clientid_len); - *iface->clientid = 255; /* RFC 4361 */ - - /* IAID is 4 bytes, so if the iface name is 4 bytes use it */ - if (strlen (iface->name) == 4) { - memcpy (iface->clientid + 1, iface->name, 4); - } else { - /* Name isn't 4 bytes, so use the index */ - uint32_t ul = htonl (if_nametoindex (iface->name)); - memcpy (iface->clientid + 1, &ul, 4); - } - - memcpy (iface->clientid + 5, duid, duid_len); - free (duid); - } else { -#else - { -#endif - iface->clientid_len = iface->hwlen + 1; - iface->clientid = xmalloc (iface->clientid_len); - *iface->clientid = iface->family; - memcpy (iface->clientid + 1, iface->hwaddr, iface->hwlen); - } - } - - return (true); -} - -static bool do_socket (state_t *state, int mode) -{ - if (state->interface->fd >= 0) - close (state->interface->fd); -#ifdef __linux - if (mode == SOCKET_CLOSED && state->interface->listen_fd >= 0) { - close (state->interface->listen_fd); - state->interface->listen_fd = -1; - } -#endif - - state->interface->fd = -1; - if (mode == SOCKET_OPEN) - if (open_socket (state->interface, ETHERTYPE_IP) == -1) - return (false); - state->socket = mode; - return (true); -} - -static bool _send_message (state_t *state, int type, const options_t *options) -{ - ssize_t retval; - - state->last_type = type; - state->last_sent = uptime (); - logSendToQt(type); - retval = send_message (state->interface, state->dhcp, state->xid, - type, options); - return (retval == -1 ? false : true); -} - -static void drop_config (state_t *state, const options_t *options) -{ - if (! state->persistent) - configure (options, state->interface, state->dhcp, false); - - free_dhcp (state->dhcp); - memset (state->dhcp, 0, sizeof (*state->dhcp)); -} - -static int wait_for_packet (struct pollfd *fds, state_t *state, - const options_t *options) -{ - dhcp_t *dhcp = state->dhcp; - interface_t *iface = state->interface; - int timeout = 0; - int retval = 0; - - if (! (state->timeout > 0 || - (options->timeout == 0 && - (state->state != STATE_INIT || state->xid)))) { - /* We need to zero our signal fd, otherwise we will block - * trying to read a signal. */ - fds[POLLFD_SIGNAL].revents = 0; - return (0); - } - - fds[POLLFD_IFACE].fd = iface->fd; - - if ((options->timeout == 0 && state->xid) || - (dhcp->leasetime == (unsigned) -1 && - state->state == STATE_BOUND)) - { - logger (LOG_DEBUG, "waiting for infinity"); - while (retval == 0) { - if (iface->fd == -1) - retval = poll (fds, 1, INFTIM); - else { - /* Slow down our requests */ - if (timeout < TIMEOUT_MINI_INF) - timeout += TIMEOUT_MINI; - else if (timeout > TIMEOUT_MINI_INF) - timeout = TIMEOUT_MINI_INF; - - retval = poll (fds, 2, timeout * 1000); - if (retval == -1 && errno == EINTR) { - /* If interupted, continue as normal as - * the signal will be delivered down - * the pipe */ - retval = 0; - continue; - } - if (retval == 0) - _send_message (state, state->last_type, - options); - } - } - - return (retval); - } - - /* Resend our message if we're getting loads of packets. - * As we use BPF or LPF, we shouldn't hit this as much, but it's - * still nice to have. */ - if (iface->fd > -1 && uptime () - state->last_sent >= TIMEOUT_MINI) - _send_message (state, state->last_type, options); - - logger (LOG_DEBUG, "waiting for %ld seconds", - (unsigned long) state->timeout); - /* If we're waiting for a reply, then we re-send the last - * DHCP request periodically in-case of a bad line */ - retval = 0; - while (state->timeout > 0 && retval == 0) { - if (iface->fd == -1) - timeout = (int) state->timeout; - else { - timeout = TIMEOUT_MINI; - if (state->timeout < timeout) - timeout = (int) state->timeout; - } - timeout *= 1000; - state->start = uptime (); - retval = poll (fds, iface->fd == -1 ? 1 : 2, timeout); - state->timeout -= uptime () - state->start; - if (retval == -1 && errno == EINTR) { - /* If interupted, continue as normal as the signal - * will be delivered down the pipe */ - retval = 0; - continue; - } - if (retval == 0 && iface->fd != -1 && state->timeout > 0) - _send_message (state, state->last_type, options); - } - - return (retval); -} - -static bool handle_signal (int sig, state_t *state, const options_t *options) -{ - switch (sig) { - case SIGINT: - logger (LOG_INFO, "received SIGINT, stopping"); - return (false); - case SIGTERM: - logger (LOG_INFO, "received SIGTERM, stopping"); - return (false); - - case SIGALRM: - logger (LOG_INFO, "received SIGALRM, renewing lease"); - switch (state->state) { - case STATE_BOUND: - case STATE_RENEWING: - case STATE_REBINDING: - state->state = STATE_RENEW_REQUESTED; - break; - case STATE_RENEW_REQUESTED: - case STATE_REQUESTING: - case STATE_RELEASED: - state->state = STATE_INIT; - break; - } - state->timeout = 0; - state->xid = 0; - return (true); - - case SIGHUP: - if (state->state != STATE_BOUND && - state->state != STATE_RENEWING && - state->state != STATE_REBINDING) - { - logger (LOG_ERR, - "received SIGHUP, but we no have lease to release"); - return (false); - } - - logger (LOG_INFO, "received SIGHUP, releasing lease"); - if (! IN_LINKLOCAL (ntohl (state->dhcp->address.s_addr))) { - do_socket (state, SOCKET_OPEN); - state->xid = (uint32_t) random (); - if ((open_socket (state->interface, false)) >= 0) { - _send_message (state, DHCP_RELEASE, options); - } - do_socket (state, SOCKET_CLOSED); - } - unlink (state->interface->infofile); - return (false); - - default: - logger (LOG_ERR, - "received signal %d, but don't know what to do with it", - sig); - } - - return (false); -} - -static int handle_timeout (state_t *state, const options_t *options) -{ - dhcp_t *dhcp = state->dhcp; - interface_t *iface = state->interface; - - /* No NAK, so reset the backoff */ - state->nakoff = 1; - - if (state->state == STATE_INIT && state->xid != 0) { - if (iface->previous_address.s_addr != 0 && - ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && - ! options->doinform) - { - logger (LOG_ERR, "lost lease"); - if (! options->persistent) - drop_config (state, options); - } else if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) - logger (LOG_ERR, "timed out"); - - do_socket (state, SOCKET_CLOSED); - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - -#ifdef ENABLE_INFO - if (! options->test && - (options->doipv4ll || options->dolastlease)) - { - errno = 0; - if (! get_old_lease (state, options)) - { - if (errno == EINTR) - return (0); - if (options->dolastlease) - return (-1); - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - } else if (errno == EINTR) - return (0); - } -#endif - -#ifdef ENABLE_IPV4LL - if (! options->test && options->doipv4ll && - (! dhcp->address.s_addr || - (! IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && - ! options->dolastlease))) - { - logger (LOG_INFO, "probing for an IPV4LL address"); - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - if (ipv4ll_get_address (iface, dhcp) == -1) { - if (! state->daemonised) - return (-1); - - /* start over */ - state->xid = 0; - return (0); - } - state->timeout = dhcp->renewaltime; - } -#endif - -#if defined (ENABLE_INFO) || defined (ENABLE_IPV4LL) - if (dhcp->address.s_addr) { - if (! state->daemonised && - IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) - logger (LOG_WARNING, "using IPV4LL address %s", - inet_ntoa (dhcp->address)); - if (configure (options, iface, dhcp, true) == -1 && - ! state->daemonised) - return (-1); - - state->state = STATE_BOUND; - if (! state->daemonised && options->daemonise) { - switch (daemonise (state->pidfd)) { - case -1: - return (-1); - case 0: - state->daemonised = true; - return (0); - default: - state->persistent = true; - state->forked = true; - return (-1); - } - } - - state->timeout = dhcp->renewaltime; - state->xid = 0; - return (0); - } -#endif - - if (! state->daemonised) - return (-1); - } - - switch (state->state) { - case STATE_INIT: - state->xid = (uint32_t) random (); - do_socket (state, SOCKET_OPEN); - state->timeout = options->timeout; - iface->start_uptime = uptime (); - if (dhcp->address.s_addr == 0) { - if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) - logger (LOG_INFO, "broadcasting for a lease"); - _send_message (state, DHCP_DISCOVER, options); - } else if (options->doinform) { - logger (LOG_INFO, "broadcasting inform for %s", - inet_ntoa (dhcp->address)); - _send_message (state, DHCP_INFORM, options); - state->state = STATE_REQUESTING; - } else { - logger (LOG_INFO, "broadcasting for a lease of %s", - inet_ntoa (dhcp->address)); - _send_message (state, DHCP_REQUEST, options); - state->state = STATE_REQUESTING; - } - - break; - case STATE_BOUND: - case STATE_RENEW_REQUESTED: - if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) { - memset (&dhcp->address, 0, sizeof (dhcp->address)); - state->state = STATE_INIT; - state->xid = 0; - break; - } - state->state = STATE_RENEWING; - state->xid = (uint32_t) random (); - /* FALLTHROUGH */ - case STATE_RENEWING: - iface->start_uptime = uptime (); - logger (LOG_INFO, "renewing lease of %s", inet_ntoa - (dhcp->address)); - do_socket (state, SOCKET_OPEN); - _send_message (state, DHCP_REQUEST, options); - state->timeout = dhcp->rebindtime - dhcp->renewaltime; - state->state = STATE_REBINDING; - break; - case STATE_REBINDING: - logger (LOG_ERR, "lost lease, attemping to rebind"); - memset (&dhcp->address, 0, sizeof (dhcp->address)); - do_socket (state, SOCKET_OPEN); - if (state->xid == 0) - state->xid = (uint32_t) random (); - dhcp->serveraddress.s_addr = 0; - _send_message (state, DHCP_REQUEST, options); - state->timeout = dhcp->leasetime - dhcp->rebindtime; - state->state = STATE_REQUESTING; - break; - case STATE_REQUESTING: - state->state = STATE_INIT; - do_socket (state, SOCKET_CLOSED); - state->timeout = 0; - break; - - case STATE_RELEASED: - dhcp->leasetime = 0; - break; - } - - return (0); -} - - -static int handle_dhcp (state_t *state, int type, const options_t *options) -{ - struct timespec ts; - interface_t *iface = state->interface; - dhcp_t *dhcp = state->dhcp; - - /* We should restart on a NAK */ - if (type == DHCP_NAK) { - logger (LOG_INFO, "received NAK: %s", dhcp->message); - logToQt(LOG_INFO, DHCP_NAK, ""); - state->state = STATE_INIT; - state->timeout = 0; - state->xid = 0; - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - - /* If we constantly get NAKS then we should slowly back off */ - if (state->nakoff > 0) { - logger (LOG_DEBUG, "sleeping for %ld seconds", - (long) state->nakoff); - ts.tv_sec = state->nakoff; - ts.tv_nsec = 0; - state->nakoff *= 2; - if (state->nakoff > NAKOFF_MAX) - state->nakoff = NAKOFF_MAX; - nanosleep (&ts, NULL); - } - - return (0); - } - - /* No NAK, so reset the backoff */ - state->nakoff = 1; - - if (type == DHCP_OFFER && state->state == STATE_INIT) { - char *addr = strdup (inet_ntoa (dhcp->address)); - if (dhcp->servername[0]) - logger (LOG_INFO, "offered %s from %s `%s'", - addr, inet_ntoa (dhcp->serveraddress), - dhcp->servername); - else - logger (LOG_INFO, "offered %s from %s", - addr, inet_ntoa (dhcp->serveraddress)); - free (addr); - - logToQt(LOG_INFO, DHCP_OFFER, ""); - -#ifdef ENABLE_INFO - if (options->test) { - write_info (iface, dhcp, options, false); - errno = 0; - return (-1); - } -#endif - - _send_message (state, DHCP_REQUEST, options); - state->state = STATE_REQUESTING; - - return (0); - } - - if (type == DHCP_OFFER) { - logger (LOG_INFO, "got subsequent offer of %s, ignoring ", - inet_ntoa (dhcp->address)); - return (0); - } - - /* We should only be dealing with acks */ - if (type != DHCP_ACK) { - logger (LOG_ERR, "%d not an ACK or OFFER", type); - return (0); - } - - /* if we are here, than we received an ACK and can go on with configuration */ - logToQt(LOG_INFO, DHCP_ACK, ""); - - switch (state->state) { - case STATE_RENEW_REQUESTED: - case STATE_REQUESTING: - case STATE_RENEWING: - case STATE_REBINDING: - break; - default: - logger (LOG_ERR, "wrong state %d", state->state); - } - - do_socket (state, SOCKET_CLOSED); - -#ifdef ENABLE_ARP - if (options->doarp && iface->previous_address.s_addr != - dhcp->address.s_addr) - { - errno = 0; - logToQt(LOG_INFO, DHCPCD_ARP_TEST, ""); - if (arp_claim (iface, dhcp->address)) { - do_socket (state, SOCKET_OPEN); - _send_message (state, DHCP_DECLINE, options); - do_socket (state, SOCKET_CLOSED); - - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - state->xid = 0; - state->timeout = 0; - state->state = STATE_INIT; - - /* RFC 2131 says that we should wait for 10 seconds - * before doing anything else */ - logger (LOG_INFO, "sleeping for 10 seconds"); - ts.tv_sec = 10; - ts.tv_nsec = 0; - nanosleep (&ts, NULL); - return (0); - } else if (errno == EINTR) - return (0); - } -#endif - - if (options->doinform) { - if (options->request_address.s_addr != 0) - dhcp->address = options->request_address; - else - dhcp->address = iface->previous_address; - - logger (LOG_INFO, "received approval for %s", - inet_ntoa (dhcp->address)); - if (iface->previous_netmask.s_addr != dhcp->netmask.s_addr) { - add_address (iface->name, dhcp->address, - dhcp->netmask, dhcp->broadcast); - iface->previous_netmask.s_addr = dhcp->netmask.s_addr; - } - state->timeout = options->leasetime; - if (state->timeout == 0) - state->timeout = DEFAULT_LEASETIME; - state->state = STATE_INIT; - } else if (dhcp->leasetime == (unsigned) -1) { - dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime; - state->timeout = 1; /* So we wait for infinity */ - logger (LOG_INFO, "leased %s for infinity", - inet_ntoa (dhcp->address)); - state->state = STATE_BOUND; - } else { - if (! dhcp->leasetime) { - dhcp->leasetime = DEFAULT_LEASETIME; - logger(LOG_INFO, - "no lease time supplied, assuming %d seconds", - dhcp->leasetime); - } - logger (LOG_INFO, "leased %s for %u seconds", - inet_ntoa (dhcp->address), dhcp->leasetime); - - if (dhcp->rebindtime >= dhcp->leasetime) { - dhcp->rebindtime = (dhcp->leasetime * 0.875); - logger (LOG_ERR, - "rebind time greater than lease " - "time, forcing to %u seconds", - dhcp->rebindtime); - } - - if (dhcp->renewaltime > dhcp->rebindtime) { - dhcp->renewaltime = (dhcp->leasetime * 0.5); - logger (LOG_ERR, - "renewal time greater than rebind time, " - "forcing to %u seconds", - dhcp->renewaltime); - } - - if (! dhcp->renewaltime) { - dhcp->renewaltime = (dhcp->leasetime * 0.5); - logger (LOG_INFO, - "no renewal time supplied, assuming %d seconds", - dhcp->renewaltime); - } else - logger (LOG_DEBUG, "renew in %u seconds", - dhcp->renewaltime); - - if (! dhcp->rebindtime) { - dhcp->rebindtime = (dhcp->leasetime * 0.875); - logger (LOG_INFO, - "no rebind time supplied, assuming %d seconds", - dhcp->rebindtime); - } else - logger (LOG_DEBUG, "rebind in %u seconds", - dhcp->rebindtime); - - state->timeout = dhcp->renewaltime; - state->state = STATE_BOUND; - } - - state->xid = 0; - - logToQt(LOG_INFO, DHCPCD_CONFIGURE, ""); - if (configure (options, iface, dhcp, true) == -1 && - ! state->daemonised) - return (-1); - - if (! state->daemonised && options->daemonise) { - switch (daemonise (state->pidfd)) { - case 0: - state->daemonised = true; - return (0); - case -1: - return (-1); - default: - state->persistent = true; - state->forked = true; - return (-1); - } - } - - return (0); -} - -static int handle_packet (state_t *state, const options_t *options) -{ - interface_t *iface = state->interface; - bool valid = false; - int type; - struct dhcp_t *new_dhcp; - dhcpmessage_t message; - - /* Allocate our buffer space for BPF. - * We cannot do this until we have opened our socket as we don't - * know how much of a buffer we need until then. */ - if (! state->buffer) - state->buffer = xmalloc (iface->buffer_length); - state->buffer_len = iface->buffer_length; - state->buffer_pos = 0; - - /* We loop through until our buffer is empty. - * The benefit is that if we get >1 DHCP packet in our buffer and - * the first one fails for any reason, we can use the next. */ - - memset (&message, 0, sizeof (message)); - new_dhcp = xmalloc (sizeof (*new_dhcp)); - - do { - if (get_packet (iface, (unsigned char *) &message, - state->buffer, - &state->buffer_len, &state->buffer_pos) == -1) - break; - - if (state->xid != message.xid) { - logger (LOG_DEBUG, - "ignoring packet with xid 0x%x as it's not ours (0x%x)", - message.xid, state->xid); - continue; - } - - logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid); - memset (new_dhcp, 0, sizeof (*new_dhcp)); - type = parse_dhcpmessage (new_dhcp, &message); - if (type == -1) { - logger (LOG_ERR, "failed to parse packet"); - free_dhcp (new_dhcp); - /* We don't abort on this, so return zero */ - return (0); - } - - /* If we got here then the DHCP packet is valid and appears to - * be for us, so let's clear the buffer as we don't care about - * any more DHCP packets at this point. */ - valid = true; - break; - } while (state->buffer_pos != 0); - - /* No packets for us, so wait until we get one */ - if (! valid) { - free (new_dhcp); - return (0); - } - - /* new_dhcp is now our master DHCP message */ - free_dhcp (state->dhcp); - free (state->dhcp); - state->dhcp = new_dhcp; - new_dhcp = NULL; - - return (handle_dhcp (state, type, options)); -} - -int dhcp_run (const options_t *options, int *pidfd) -{ - interface_t *iface; - state_t *state = NULL; - struct pollfd fds[] = { - { -1, POLLIN, 0 }, - { -1, POLLIN, 0 } - }; - int retval = -1; - int sig; - - if (! options) - return (-1); - - /*read_interface : defined in interface.c*/ - iface = read_interface (options->interface, options->metric); - if (! iface) - goto eexit; - - state = xzalloc (sizeof (*state)); - state->dhcp = xzalloc (sizeof (*state->dhcp)); - state->pidfd = pidfd; - state->interface = iface; - - if (! client_setup (state, options)) - goto eexit; - - if (signal_init () == -1) - goto eexit; - if (signal_setup () == -1) - goto eexit; - - fds[POLLFD_SIGNAL].fd = signal_fd (); - - for (;;) { - retval = wait_for_packet (fds, state, options); - - /* We should always handle our signals first */ - if ((sig = (signal_read (&fds[POLLFD_SIGNAL]))) != -1) { - if (handle_signal (sig, state, options)) - retval = 0; - else - retval = -1; - } else if (retval == 0) - retval = handle_timeout (state, options); - else if (retval > 0 && - state->socket != SOCKET_CLOSED && - fds[POLLFD_IFACE].revents & POLLIN) - retval = handle_packet (state, options); - else if (retval == -1 && errno == EINTR) { - /* The interupt will be handled above */ - retval = 0; - } else { - logger (LOG_ERR, "poll: %s", strerror (errno)); - retval = -1; - } - - if (retval != 0) - break; - } - -eexit: - if (iface) { - do_socket (state, SOCKET_CLOSED); - drop_config (state, options); - free_route (iface->previous_routes); - free (iface->clientid); - free (iface); - } - - if (state) { - if (state->forked) - retval = 0; - - if (state->daemonised) - unlink (options->pidfile); - - free_dhcp (state->dhcp); - free (state->dhcp); - free (state->buffer); - free (state); - } - - return (retval); -} diff --git a/customdhcpcd/src/client.h b/customdhcpcd/src/client.h deleted file mode 100644 index fa6ea9b..0000000 --- a/customdhcpcd/src/client.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CLIENT_H -#define CLIENT_H - -#include "dhcpcd.h" - -int dhcp_run (const options_t *options, int *pidfd); - -#endif diff --git a/customdhcpcd/src/common.c b/customdhcpcd/src/common.c deleted file mode 100644 index 99471bc..0000000 --- a/customdhcpcd/src/common.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "logger.h" - -/* Handy routine to read very long lines in text files. - * This means we read the whole line and avoid any nasty buffer overflows. */ -char *get_line (FILE *fp) -{ - char *line = NULL; - char *p; - size_t len = 0; - size_t last = 0; - - if (feof (fp)) - return (NULL); - - do { - len += BUFSIZ; - line = xrealloc (line, sizeof (char) * len); - p = line + last; - memset (p, 0, BUFSIZ); - fgets (p, BUFSIZ, fp); - last += strlen (p); - } while (! feof (fp) && line[last - 1] != '\n'); - - /* Trim the trailing newline */ - if (*line && line[--last] == '\n') - line[last] = '\0'; - - return (line); -} - -/* OK, this should be in dhcpcd.c - * It's here to make dhcpcd more readable */ -#ifndef HAVE_SRANDOMDEV -void srandomdev (void) -{ - int fd; - unsigned long seed; - - fd = open ("/dev/urandom", 0); - if (fd == -1 || read (fd, &seed, sizeof (seed)) == -1) { - logger (LOG_WARNING, "Could not read from /dev/urandom: %s", - strerror (errno)); - seed = time (0); - } - if (fd >= 0) - close(fd); - - srandom (seed); -} -#endif - -/* strlcpy is nice, shame glibc does not define it */ -#ifndef HAVE_STRLCPY -size_t strlcpy (char *dst, const char *src, size_t size) -{ - const char *s = src; - size_t n = size; - - if (n && --n) - do { - if (! (*dst++ = *src++)) - break; - } while (--n); - - if (! n) { - if (size) - *dst = '\0'; - while (*src++); - } - - return (src - s - 1); -} -#endif - -/* Close our fd's */ -int close_fds (void) -{ - int fd; - - if ((fd = open ("/dev/null", O_RDWR)) == -1) { - logger (LOG_ERR, "open `/dev/null': %s", strerror (errno)); - return (-1); - } - - dup2 (fd, fileno (stdin)); - dup2 (fd, fileno (stdout)); - dup2 (fd, fileno (stderr)); - if (fd > 2) - close (fd); - return (0); -} - -int close_on_exec (int fd) -{ - int flags; - - if ((flags = fcntl (fd, F_GETFD, 0)) == -1 - || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1) - { - logger (LOG_ERR, "fcntl: %s", strerror (errno)); - return (-1); - } - return (0); -} - -/* Handy function to get the time. - * We only care about time advancements, not the actual time itself - * Which is why we use CLOCK_MONOTONIC, but it is not available on all - * platforms. - */ -int get_time (struct timeval *tp) -{ -#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC) - struct timespec ts; - static clockid_t posix_clock; - static int posix_clock_set = 0; - - if (! posix_clock_set) { - if (sysconf (_SC_MONOTONIC_CLOCK) >= 0) - posix_clock = CLOCK_MONOTONIC; - else - posix_clock = CLOCK_REALTIME; - posix_clock_set = 1; - } - - if (clock_gettime (posix_clock, &ts) == -1) { - logger (LOG_ERR, "clock_gettime: %s", strerror (errno)); - return (-1); - } - - tp->tv_sec = ts.tv_sec; - tp->tv_usec = ts.tv_nsec / 1000; - return (0); -#else - if (gettimeofday (tp, NULL) == -1) { - logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); - return (-1); - } - return (0); -#endif -} - -time_t uptime (void) -{ - struct timeval tp; - - if (get_time (&tp) == -1) - return (-1); - - return (tp.tv_sec); -} - -void writepid (int fd, pid_t pid) -{ - char spid[16]; - if (ftruncate (fd, (off_t) 0) == -1) { - logger (LOG_ERR, "ftruncate: %s", strerror (errno)); - } else { - ssize_t len; - snprintf (spid, sizeof (spid), "%u", pid); - len = pwrite (fd, spid, strlen (spid), (off_t) 0); - if (len != (ssize_t) strlen (spid)) - logger (LOG_ERR, "pwrite: %s", strerror (errno)); - } -} - -void *xmalloc (size_t s) -{ - void *value = malloc (s); - - if (value) - return (value); - - logger (LOG_ERR, "memory exhausted"); - - exit (EXIT_FAILURE); - /* NOTREACHED */ -} - -void *xzalloc (size_t s) -{ - void *value = xmalloc (s); - memset (value, 0, s); - return (value); -} - -void *xrealloc (void *ptr, size_t s) -{ - void *value = realloc (ptr, s); - - if (value) - return (value); - - logger (LOG_ERR, "memory exhausted"); - exit (EXIT_FAILURE); - /* NOTREACHED */ -} - -char *xstrdup (const char *str) -{ - char *value; - - if (! str) - return (NULL); - - if ((value = strdup (str))) - return (value); - - logger (LOG_ERR, "memory exhausted"); - exit (EXIT_FAILURE); - /* NOTREACHED */ -} diff --git a/customdhcpcd/src/common.h b/customdhcpcd/src/common.h deleted file mode 100644 index 46f1886..0000000 --- a/customdhcpcd/src/common.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef COMMON_H -#define COMMON_H - -/* string.h pulls in features.h so the below define checks work */ -#include -#include -#include - -#if __GNUC__ > 2 || defined(__INTEL_COMPILER) -# define _unused __attribute__((__unused__)) -#else -# define _unused -#endif - -#define HAVE_STRLCPY -/* Only GLIBC doesn't support strlcpy */ -#ifdef __GLIBC__ -# if ! defined(__UCLIBC__) && ! defined (__dietlibc__) -# undef HAVE_STRLCPY -size_t strlcpy (char *dst, const char *src, size_t size); -# endif -#endif - -#define HAVE_SRANDOMDEV -#if defined(__GLIBC__) || defined(__NetBSD__) -# undef HAVE_SRANDOMDEV -void srandomdev (void); -#endif - -int close_fds (void); -int close_on_exec (int fd); -char *get_line (FILE *fp); -int get_time (struct timeval *tp); -time_t uptime (void); -void writepid (int fd, pid_t pid); -void *xrealloc (void *ptr, size_t size); -void *xmalloc (size_t size); -void *xzalloc (size_t size); -char *xstrdup (const char *str); - -#endif diff --git a/customdhcpcd/src/config.h b/customdhcpcd/src/config.h deleted file mode 100644 index 2c0991b..0000000 --- a/customdhcpcd/src/config.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef CONFIG_H -#define CONFIG_H - -/* You can enable/disable various chunks of optional code here. - * You would only do this to try and shrink the end binary if dhcpcd - * was running on a low memory device */ - -#define ENABLE_ARP -#define ENABLE_NTP -#define ENABLE_NIS -#define ENABLE_INFO -/* Define this to enable some compatability with 1.x and 2.x info files */ -/* #define ENABLE_INFO_COMPAT */ - -/* IPV4LL, aka ZeroConf, aka APIPA, aka RFC 3927. - * Needs ARP. */ -#define ENABLE_IPV4LL - -/* We will auto create a DUID_LLT file if it doesn't exist. - * You can always create your own DUID file that just contains the - * hex string that represents the DUID. - * See RFC 3315 for details on this. */ -#define ENABLE_DUID - -/* resolvconf is framework for multiple interfaces to manage resolv.conf */ -#define ENABLE_RESOLVCONF - -/* Some systems do not have a working fork. - * The Makefile will attempt to work it out, but if it fails to feel free to - * define it here. */ -/* #define THERE_IS_NO_FORK */ - -/* Packname name and pathname definitions. */ - -#define PACKAGE "dhcpcd" - -#define ETCDIR "/etc" -#define RESOLVFILE ETCDIR "/resolv.conf" - -#define NISFILE ETCDIR "/yp.conf" - -#define NTPFILE ETCDIR "/ntp.conf" -#define NTPDRIFTFILE ETCDIR "/ntp.drift" -#define NTPLOGFILE "/var/log/ntp.log" - -#define OPENNTPFILE ETCDIR "/ntpd.conf" - -#define DEFAULT_SCRIPT ETCDIR "/" PACKAGE ".sh" - -#define STATEDIR "/var" -#define PIDFILE STATEDIR "/run/" PACKAGE "-%s.pid" - -#ifndef INFODIR -# define INFODIR "/var/lib/dhcpcd" -#endif -#define INFOFILE INFODIR "/" PACKAGE "-%s.info" -#define DUIDFILE INFODIR "/" PACKAGE ".duid" - -/* OPENRC is Open Run Control, forked from Gentoo's baselayout package - * BSDRC is BSD style Run Control - * SLACKRC is Slackware Run Control - * SERVICE is RedHat service command - * SYSV should cover everthing else */ -#ifdef ENABLE_OPENRC -# define SERVICE "OPENRC" -# define NISSERVICE ETCDIR "/init.d/ypbind" -# define NISRESTARTARGS "--nodeps", "--quiet", "conditionalrestart" -# define NTPSERVICE ETCDIR "/init.d/ntpd" -# define NTPRESTARTARGS "--nodeps", "--quiet", "conditionalrestart" -#endif -#if ENABLE_BSDRC -# define SERVICE "BSDRC" -# define NISSERVICE ETCDIR "/rc.d/ypbind" -# define NISRESTARTARGS "restart" -# define NTPSERVICE ETCDIR "/rc.d/ntpd" -# define NTPRESTARTARGS "restart" -#endif -#if ENABLE_SLACKRC -# define SERVICE "SLACKRC" -# define NISSERVICE ETCDIR "/rc.d/rc.ypbind" -# define NISRESTARTARGS "restart" -# define NTPSERVICE ETCDIR "/rc.d/rc.ntpd" -# define NTPRESTARTARGS "restart" -#endif -#if ENABLE_SERVICE -# define SERVICE "SERVICE" -# define NISSERVICE "service" -# define NISRESTARTARGS "ypbind", "restart" -# define NTPSERVICE "service" -# define NTPRESTARTARGS "ntpd", "restart" -#endif -#if ENABLE_SYSV -# define SERVICE "SYSV" -# define NISSERVICE ETCDIR "/init.d/ypbind" -# define NISRESTARTARGS "restart" -# define NTPSERVICE ETCDIR "/init.d/ntpd" -# define NTPRESTARTARGS "restart" -#endif - -#ifndef NISSERVICE -# undef ENABLE_NIS -#endif -#ifndef NTPSERVICE -# undef ENABLE_NTP -#endif - -#endif diff --git a/customdhcpcd/src/configure.c b/customdhcpcd/src/configure.c deleted file mode 100644 index b69ccdc..0000000 --- a/customdhcpcd/src/configure.c +++ /dev/null @@ -1,814 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#ifdef __linux__ -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "common.h" -#include "configure.h" -#include "dhcp.h" -#ifdef ENABLE_INFO -# include "info.h" -#endif -#include "interface.h" -#include "dhcpcd.h" -#include "logger.h" -#include "signal.h" -#include "socket.h" - -#include "logwriter.h" - -static int file_in_path (const char *file) -{ - char *p = getenv ("PATH"); - char *path; - char *token; - struct stat s; - char mypath[PATH_MAX]; - int retval = -1; - - if (! p) { - errno = ENOENT; - return (-1); - } - - path = strdup (p); - p = path; - while ((token = strsep (&p, ":"))) { - snprintf (mypath, PATH_MAX, "%s/%s", token, file); - if (stat (mypath, &s) == 0) { - retval = 0; - break; - } - } - free (path); - return (retval); -} - -/* IMPORTANT: Ensure that the last parameter is NULL when calling */ -static int exec_cmd (const char *cmd, const char *args, ...) -{ - va_list va; - char **argv; - int n = 1; - int ret = 0; - pid_t pid; - sigset_t full; - sigset_t old; - - va_start (va, args); - while (va_arg (va, char *) != NULL) - n++; - va_end (va); - argv = xmalloc (sizeof (char *) * (n + 2)); - - va_start (va, args); - n = 2; - argv[0] = (char *) cmd; - argv[1] = (char *) args; - while ((argv[n] = va_arg (va, char *)) != NULL) - n++; - va_end (va); - - /* OK, we need to block signals */ - sigfillset (&full); - sigprocmask (SIG_SETMASK, &full, &old); - -#ifdef THERE_IS_NO_FORK - signal_reset (); - pid = vfork (); -#else - pid = fork(); -#endif - - switch (pid) { - case -1: - logger (LOG_ERR, "vfork: %s", strerror (errno)); - ret = -1; - break; - case 0: -#ifndef THERE_IS_NO_FORK - signal_reset (); -#endif - sigprocmask (SIG_SETMASK, &old, NULL); - if (execvp (cmd, argv) && errno != ENOENT) - logger (LOG_ERR, "error executing \"%s\": %s", - cmd, strerror (errno)); - _exit (111); - /* NOTREACHED */ - } - -#ifdef THERE_IS_NO_FORK - signal_setup (); -#endif - - /* Restore our signals */ - sigprocmask (SIG_SETMASK, &old, NULL); - - free (argv); - return (ret); -} - -static void exec_script (const char *script, const char *infofile, - const char *arg) -{ - struct stat buf; - - if (! script || ! infofile || ! arg) - return; - - if (stat (script, &buf) == -1) { - if (strcmp (script, DEFAULT_SCRIPT) != 0) - logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT)); - return; - } - -#ifdef ENABLE_INFO - logger (LOG_DEBUG, "exec \"%s\" \"%s\" \"%s\"", script, infofile, arg); - exec_cmd (script, infofile, arg, (char *) NULL); -#else - logger (LOG_DEBUG, "exec \"%s\" \"\" \"%s\"", script, arg); - exec_cmd (script, "", arg, (char *) NULL); -#endif -} - -static int make_resolv (const char *ifname, const dhcp_t *dhcp) -{ - FILE *f = NULL; - address_t *address; - -#ifdef ENABLE_RESOLVCONF - char *resolvconf = NULL; - - if (file_in_path ("resolvconf") == 0) { - size_t len = strlen ("resolvconf -a ") + strlen (ifname) + 1; - resolvconf = xmalloc (sizeof (char) * len); - snprintf (resolvconf, len, "resolvconf -a %s", ifname); - if ((f = popen (resolvconf , "w"))) - logger (LOG_DEBUG, - "sending DNS information to resolvconf"); - else if (errno == EEXIST) - logger (LOG_ERR, "popen: %s", strerror (errno)); - - if (ferror (f)) - logger (LOG_ERR, "ferror"); - free (resolvconf); - } -#endif - if (! f) { - logger (LOG_DEBUG, "writing "RESOLVFILE); - if (! (f = fopen(RESOLVFILE, "w"))) - logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno)); - } - - if (! f) - return (-1); - - fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); - if (dhcp->dnssearch) - fprintf (f, "search %s\n", dhcp->dnssearch); - else if (dhcp->dnsdomain) { - fprintf (f, "search %s\n", dhcp->dnsdomain); - } - - STAILQ_FOREACH (address, dhcp->dnsservers, entries) - fprintf (f, "nameserver %s\n", inet_ntoa (address->address)); - -#ifdef ENABLE_RESOLVCONF - if (resolvconf) - pclose (f); - else -#endif - fclose (f); - - /* Refresh the local resolver */ - res_init (); - return (0); -} - -static void restore_resolv (const char *ifname) -{ -#ifdef ENABLE_RESOLVCONF - if (file_in_path ("resolvconf") == 0) { - logger (LOG_DEBUG, "removing information from resolvconf"); - exec_cmd("resolvconf", "-d", ifname, (char *) NULL); - } -#endif -} - -static bool in_addresses (const struct address_head *addresses, - struct in_addr address) -{ - const address_t *addr; - - STAILQ_FOREACH (addr, addresses, entries) - if (addr->address.s_addr == address.s_addr) - return (true); - - return (false); -} - -static bool in_routes (const struct route_head *routes, route_t *route) -{ - const route_t *r; - - if (! routes) - return (false); - - STAILQ_FOREACH (r, routes, entries) - if (r->destination.s_addr == route->destination.s_addr && - r->netmask.s_addr == route->netmask.s_addr && - r->gateway.s_addr == route->gateway.s_addr) - return (true); - - return (false); -} - -#ifdef ENABLE_NTP -static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) -{ - FILE *f; - address_t *address; - char *a; - char *line; - int tomatch = 0; - char *token; - bool ntp = false; - - STAILQ_FOREACH (address, dhcp->ntpservers, entries) - tomatch++; - - /* Check that we really need to update the servers. - * We do this because ntp has to be restarted to - * work with a changed config. */ - if (! (f = fopen (file, "r"))) { - if (errno != ENOENT) { - logger (LOG_ERR, "fopen `%s': %s", - file, strerror (errno)); - return (-1); - } - } else { - while (tomatch != 0 && (line = get_line (f))) { - struct in_addr addr; - - a = line; - token = strsep (&a, " "); - if (! token || strcmp (token, "server") != 0) - goto next; - - if ((token = strsep (&a, " \n")) == NULL) - goto next; - - if (inet_aton (token, &addr) == 1 && - in_addresses (dhcp->ntpservers, addr)) - tomatch--; - -next: - free (line); - } - fclose (f); - - /* File has the same name servers that we do, - * so no need to restart ntp */ - if (tomatch == 0) { - logger (LOG_DEBUG, "%s already configured, skipping", - file); - return (0); - } - } - - logger (LOG_DEBUG, "writing %s", file); - if (! (f = fopen (file, "w"))) { - logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno)); - return (-1); - } - - fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); -#ifdef NTPFILE - if (strcmp (file, NTPFILE) == 0) { - ntp = true; - fprintf (f, "restrict default noquery notrust nomodify\n"); - fprintf (f, "restrict 127.0.0.1\n"); - } -#endif - - STAILQ_FOREACH (address, dhcp->ntpservers, entries) { - a = inet_ntoa (address->address); - if (ntp) - fprintf (f, "restrict %s nomodify notrap noquery\n", a); - fprintf (f, "server %s\n", a); - } - fclose (f); - - return (1); -} - -static int make_ntp (const char *ifname, const dhcp_t *dhcp) -{ - /* On some systems we have only have one ntp service, but we don't - * know which configuration file we're using. So we need to write - * to both and restart accordingly. */ - - bool restart_ntp = false; - bool restart_openntp = false; - int retval = 0; - -#ifdef NTPFILE - if (_make_ntp (NTPFILE, ifname, dhcp) > 0) - restart_ntp = true; -#endif - -#ifdef OPENNTPFILE - if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0) - restart_openntp = true; -#endif - -#ifdef NTPSERVICE - if (restart_ntp) { -#ifdef NTPCHECK - if (system (NTPCHECK) == 0) -#endif - retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, - (char *) NULL); - } -#endif - -#if defined (NTPSERVICE) && defined (OPENNTPSERVICE) - if (restart_openntp && - (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp)) - { -#ifdef OPENNTPCHECK - if (system (OPENNTPCHECK) == 0) -#endif - retval += exec_cmd (OPENNTPSERVICE, - OPENNTPRESTARTARGS, (char *) NULL); - } -#elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE) - if (restart_openntp) { -#ifdef OPENNTPCHECK - if (system (OPENNTPCHECK) == 0) -#endif - retval += exec_cmd (OPENNTPSERVICE, - OPENNTPRESTARTARGS, (char *) NULL); - } -#endif - - return (retval); -} -#endif - -#ifdef ENABLE_NIS -#define PREFIXSIZE 256 -static int make_nis (const char *ifname, const dhcp_t *dhcp) -{ - FILE *f; - address_t *address; - char *prefix; - - logger (LOG_DEBUG, "writing "NISFILE); - if (! (f = fopen(NISFILE, "w"))) { - logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno)); - return (-1); - } - - prefix = xmalloc (sizeof (char) * PREFIXSIZE); - *prefix = '\0'; - fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); - - if (dhcp->nisdomain) { - setdomainname (dhcp->nisdomain, (int) strlen (dhcp->nisdomain)); - - if (dhcp->nisservers) - snprintf (prefix, PREFIXSIZE, "domain %s server", - dhcp->nisdomain); - else - fprintf (f, "domain %s broadcast\n", dhcp->nisdomain); - } - else - snprintf (prefix, PREFIXSIZE, "%s", "ypserver"); - - NSTAILQ_FOREACH (address, dhcp->nisservers, entries) - fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address)); - - free (prefix); - fclose (f); - -#ifdef NISCHECK - if (system (NISCHECK) == 0) -#endif - exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL); - return (0); -} -#endif - -static char *lookuphostname (char *hostname, const dhcp_t *dhcp, - const options_t *options) -{ - union { - struct sockaddr sa; - struct sockaddr_in sin; - } su; - socklen_t salen; - char *addr; - struct addrinfo hints; - struct addrinfo *res = NULL; - int result; - char *p; - - logger (LOG_DEBUG, "Looking up hostname via DNS"); - addr = xmalloc (sizeof (char) * NI_MAXHOST); - salen = sizeof (su.sa); - memset (&su.sa, 0, salen); - su.sin.sin_family = AF_INET; - memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (su.sin.sin_addr)); - - if ((result = getnameinfo (&su.sa, salen, addr, NI_MAXHOST, - NULL, 0, NI_NAMEREQD)) != 0) { - logger (LOG_ERR, - "Failed to lookup hostname via DNS: %s", - gai_strerror (result)); - free (addr); - return (NULL); - } - - /* Check for a malicious PTR record */ - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICHOST; - result = getaddrinfo (addr, "0", &hints, &res); - if (res) - freeaddrinfo (res); - if (result == 0) - logger (LOG_ERR, "malicious PTR record detected"); - if (result == 0 || ! *addr) { - free (addr); - return (NULL); - } - - p = strchr (addr, '.'); - if (p) { - switch (options->dohostname) { - case 1: /* -H */ - case 4: /* -HHHH */ - break; - case 2: /* -HH */ - case 5: /* -HHHHH */ - /* Strip out the domain if it matches */ - p++; - if (*p && dhcp->dnssearch) { - char *s = xstrdup (dhcp->dnssearch); - char *sp = s; - char *t; - - while ((t = strsep (&sp, " "))) - if (strcmp (t, p) == 0) { - *--p = '\0'; - break; - } - free (s); - } else if (dhcp->dnsdomain) { - if (strcmp (dhcp->dnsdomain, p) == 0) - *--p = '\0'; - } - break; - case 3: /* -HHH */ - case 6: /* -HHHHHH */ - /* Just strip the domain */ - *p = '\0'; - break; - default: /* Too many H! */ - break; - } - } - - strlcpy (hostname, addr, MAXHOSTNAMELEN); - free (addr); - return (hostname); -} - -int configure (const options_t *options, interface_t *iface, - const dhcp_t *dhcp, bool up) -{ - route_t *route = NULL; - struct route_head *new_routes = NULL; - route_t *new_route = NULL; - char *newhostname = NULL; - char *curhostname = NULL; - int remember; -#ifdef ENABLE_IPV4LL - bool haslinklocal = false; -#endif -#ifdef THERE_IS_NO_FORK - int skip = 0; - size_t skiplen; - char *skipp; -#endif - - if (! options || ! iface || ! dhcp) - return (-1); - - if (dhcp->address.s_addr == 0) - up = 0; - - logGatewayToFile(iface, dhcp); - - /* Remove old routes. - * Always do this as the interface may have >1 address not added by us - * so the routes we added may still exist. */ - NSTAILQ_FOREACH (route, iface->previous_routes, entries) - if ((route->destination.s_addr || options->dogateway) && - (! up || ! in_routes (dhcp->routes, route))) - del_route (iface->name, route->destination, - route->netmask, route->gateway, - options->metric); - /* If we aren't up, then reset the interface as much as we can */ - if (! up) { - if (iface->previous_routes) { - free_route (iface->previous_routes); - iface->previous_routes = NULL; - } - - /* Restore the original MTU value */ - if (iface->mtu && iface->previous_mtu != iface->mtu) { - set_mtu (iface->name, iface->mtu); - iface->previous_mtu = iface->mtu; - } - -#ifdef ENABLE_INFO - /* If we haven't created an info file, do so now */ - if (! dhcp->frominfo) - write_info (iface, dhcp, options, false); -#endif - - /* Only reset things if we had set them before */ - if (iface->previous_address.s_addr != 0) { - if (! options->keep_address) { - del_address (iface->name, - iface->previous_address, - iface->previous_netmask); - memset (&iface->previous_address, - 0, sizeof (iface->previous_address)); - memset (&iface->previous_netmask, - 0, sizeof (iface->previous_netmask)); - } - } - - restore_resolv (iface->name); - exec_script (options->script, iface->infofile, "down"); - - return (0); - } - - /* Set the MTU requested. - * If the DHCP server no longer sends one OR it's invalid then - * we restore the original MTU */ - if (options->domtu) { - unsigned short mtu = iface->mtu; - if (dhcp->mtu) - mtu = dhcp->mtu; - - if (mtu != iface->previous_mtu) { - if (set_mtu (iface->name, mtu) == 0) - iface->previous_mtu = mtu; - } - } - - /* This also changes netmask */ - if (! options->doinform || ! has_address (iface->name, dhcp->address)) - if (add_address (iface->name, dhcp->address, dhcp->netmask, - dhcp->broadcast) == -1 && errno != EEXIST) - return (false); - - /* Now delete the old address if different */ - if (iface->previous_address.s_addr != dhcp->address.s_addr && - iface->previous_address.s_addr != 0 && - ! options->keep_address) - del_address (iface->name, - iface->previous_address, iface->previous_netmask); - -#ifdef __linux__ - /* On linux, we need to change the subnet route to have our metric. */ - if (iface->previous_address.s_addr != dhcp->address.s_addr && - options->metric > 0 && - dhcp->netmask.s_addr != INADDR_BROADCAST) - { - struct in_addr td; - struct in_addr tg; - memset (&td, 0, sizeof (td)); - memset (&tg, 0, sizeof (tg)); - td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; - add_route (iface->name, td, dhcp->netmask, tg, options->metric); - del_route (iface->name, td, dhcp->netmask, tg, 0); - } -#endif - -#ifdef THERE_IS_NO_FORK - free (dhcpcd_skiproutes); - /* We can never have more than 255 routes. So we need space - * for 255 3 digit numbers and commas */ - skiplen = 255 * 4 + 1; - skipp = dhcpcd_skiproutes = xmalloc (sizeof (char) * skiplen); - *skipp = '\0'; -#endif - - /* Remember added routes */ - NSTAILQ_FOREACH (route, dhcp->routes, entries) { -#ifdef ENABLE_IPV4LL - /* Check if we have already got a link locale route dished - * out by the DHCP server */ - if (route->destination.s_addr == htonl (LINKLOCAL_ADDR) && - route->netmask.s_addr == htonl (LINKLOCAL_MASK)) - haslinklocal = true; -#endif - /* Don't set default routes if not asked to */ - if (route->destination.s_addr == 0 && - route->netmask.s_addr == 0 && - ! options->dogateway) - continue; - - remember = add_route (iface->name, route->destination, - route->netmask, route->gateway, - options->metric); - /* If we failed to add the route, we may have already added it - ourselves. If so, remember it again. */ - if (remember < 0 && in_routes (iface->previous_routes, route)) - remember = 1; - - if (remember >= 0) { - if (! new_routes) { - new_routes = xmalloc (sizeof (*new_routes)); - STAILQ_INIT (new_routes); - } - new_route = xmalloc (sizeof (route_t)); - memcpy (new_route, route, sizeof (*new_route)); - STAILQ_INSERT_TAIL (new_routes, new_route, entries); - } -#ifdef THERE_IS_NO_FORK - /* If we have daemonised yet we need to record which routes - * we failed to add so we can skip them */ - else if (! options->daemonised) { - /* We can never have more than 255 / 4 routes, - * so 3 chars is plently */ - if (*skipp) - *skipp++ = ','; - skipp += snprintf (skipp, - dhcpcd_skiproutes + skiplen - skipp, - "%d", skip); - } - skip++; -#endif - } - -#ifdef THERE_IS_NO_FORK - if (*dhcpcd_skiproutes) - *skipp = '\0'; - else { - free (dhcpcd_skiproutes); - dhcpcd_skiproutes = NULL; - } -#endif - -#ifdef ENABLE_IPV4LL - /* Ensure we always add the link local route if we got a private - * address and isn't link local itself */ - if (options->doipv4ll && - ! haslinklocal && - IN_PRIVATE (ntohl (dhcp->address.s_addr))) - { - struct in_addr dest; - struct in_addr mask; - struct in_addr gate; - - dest.s_addr = htonl (LINKLOCAL_ADDR); - mask.s_addr = htonl (LINKLOCAL_MASK); - gate.s_addr = 0; - remember = add_route (iface->name, dest, mask, gate, - options->metric); - - if (remember >= 0) { - if (! new_routes) { - new_routes = xmalloc (sizeof (*new_routes)); - STAILQ_INIT (new_routes); - } - new_route = xmalloc (sizeof (*new_route)); - new_route->destination.s_addr = dest.s_addr; - new_route->netmask.s_addr = mask.s_addr; - new_route->gateway.s_addr = gate.s_addr; - STAILQ_INSERT_TAIL (new_routes, new_route, entries); - } - } -#endif - - if (iface->previous_routes) - free_route (iface->previous_routes); - iface->previous_routes = new_routes; - - logToQt(LOG_INFO, DHCPCD_WRITE, ""); - if (options->dodns && dhcp->dnsservers) - make_resolv(iface->name, dhcp); - else - logger (LOG_DEBUG, "no dns information to write"); - -#ifdef ENABLE_NTP - if (options->dontp && dhcp->ntpservers) - make_ntp(iface->name, dhcp); -#endif - -#ifdef ENABLE_NIS - if (options->donis && (dhcp->nisservers || dhcp->nisdomain)) - make_nis(iface->name, dhcp); -#endif - - curhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); - *curhostname = '\0'; - - gethostname (curhostname, MAXHOSTNAMELEN); - if (options->dohostname || - strlen (curhostname) == 0 || - strcmp (curhostname, "(none)") == 0 || - strcmp (curhostname, "localhost") == 0) - { - newhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); - - if (dhcp->hostname) - strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN); - else - *newhostname = '\0'; - - /* Now we have made a resolv.conf we can obtain a hostname - * if we need it */ - if (! *newhostname || options->dohostname > 3) - lookuphostname (newhostname, dhcp, options); - - if (*newhostname) { - logger (LOG_INFO, "setting hostname to `%s'", - newhostname); - sethostname (newhostname, (int) strlen (newhostname)); - } - - free (newhostname); - } - - free (curhostname); - -#ifdef ENABLE_INFO - if (! dhcp->frominfo) - write_info (iface, dhcp, options, true); -#endif - - if (iface->previous_address.s_addr != dhcp->address.s_addr || - iface->previous_netmask.s_addr != dhcp->netmask.s_addr) - { - memcpy (&iface->previous_address, - &dhcp->address, sizeof (iface->previous_address)); - memcpy (&iface->previous_netmask, - &dhcp->netmask, sizeof (iface->previous_netmask)); - exec_script (options->script, iface->infofile, "new"); - } else - exec_script (options->script, iface->infofile, "up"); - - return (0); -} diff --git a/customdhcpcd/src/configure.h b/customdhcpcd/src/configure.h deleted file mode 100644 index 3166947..0000000 --- a/customdhcpcd/src/configure.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef DHCPCONFIG_H -#define DHCPCONFIG_H - -#include "dhcpcd.h" -#include "interface.h" -#include "dhcp.h" - -int configure (const options_t *options, interface_t *iface, - const dhcp_t *dhcp, bool up); - -#endif diff --git a/customdhcpcd/src/dhcp.c b/customdhcpcd/src/dhcp.c deleted file mode 100644 index f625e8f..0000000 --- a/customdhcpcd/src/dhcp.c +++ /dev/null @@ -1,933 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#include "common.h" -#include "dhcpcd.h" -#include "dhcp.h" -#include "interface.h" -#include "logger.h" -#include "socket.h" - -#ifndef STAILQ_CONCAT -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ -} while (0) -#endif - -typedef struct message { - int value; - const char *name; -} dhcp_message_t; - -static dhcp_message_t dhcp_messages[] = { - { DHCP_DISCOVER, "DHCP_DISCOVER" }, - { DHCP_OFFER, "DHCP_OFFER" }, - { DHCP_REQUEST, "DHCP_REQUEST" }, - { DHCP_DECLINE, "DHCP_DECLINE" }, - { DHCP_ACK, "DHCP_ACK" }, - { DHCP_NAK, "DHCP_NAK" }, - { DHCP_RELEASE, "DHCP_RELEASE" }, - { DHCP_INFORM, "DHCP_INFORM" }, - { -1, NULL } -}; - -static const char *dhcp_message (int type) -{ - dhcp_message_t *d; - for (d = dhcp_messages; d->name; d++) - if (d->value == type) - return (d->name); - - return (NULL); -} - -ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp, - uint32_t xid, char type, const options_t *options) -{ - struct udp_dhcp_packet *packet; - dhcpmessage_t *message; - unsigned char *m; - unsigned char *p; - unsigned char *n_params = NULL; - size_t l; - struct in_addr from; - struct in_addr to; - time_t up = uptime() - iface->start_uptime; - uint32_t ul; - uint16_t sz; - size_t message_length; - ssize_t retval; - - if (!iface || !options || !dhcp) - return -1; - - memset (&from, 0, sizeof (from)); - memset (&to, 0, sizeof (to)); - - if (type == DHCP_RELEASE) - to.s_addr = dhcp->serveraddress.s_addr; - - message = xzalloc (sizeof (*message)); - m = (unsigned char *) message; - p = (unsigned char *) &message->options; - - if ((type == DHCP_INFORM || - type == DHCP_RELEASE || - type == DHCP_REQUEST) && - ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) - { - message->ciaddr = iface->previous_address.s_addr; - from.s_addr = iface->previous_address.s_addr; - - /* Just incase we haven't actually configured the address yet */ - if (type == DHCP_INFORM && iface->previous_address.s_addr == 0) - message->ciaddr = dhcp->address.s_addr; - - /* Zero the address if we're currently on a different subnet */ - if (type == DHCP_REQUEST && - iface->previous_netmask.s_addr != dhcp->netmask.s_addr) - message->ciaddr = from.s_addr = 0; - - if (from.s_addr != 0) - to.s_addr = dhcp->serveraddress.s_addr; - } - - message->op = DHCP_BOOTREQUEST; - message->hwtype = iface->family; - switch (iface->family) { - case ARPHRD_ETHER: - case ARPHRD_IEEE802: - message->hwlen = ETHER_ADDR_LEN; - memcpy (&message->chaddr, &iface->hwaddr, - ETHER_ADDR_LEN); - break; - case ARPHRD_IEEE1394: - case ARPHRD_INFINIBAND: - message->hwlen = 0; - if (message->ciaddr == 0) - message->flags = htons (BROADCAST_FLAG); - break; - default: - logger (LOG_ERR, "dhcp: unknown hardware type %d", - iface->family); - } - - if (up < 0 || up > (time_t) UINT16_MAX) - message->secs = htons ((uint16_t) UINT16_MAX); - else - message->secs = htons (up); - message->xid = xid; - message->cookie = htonl (MAGIC_COOKIE); - - *p++ = DHCP_MESSAGETYPE; - *p++ = 1; - *p++ = type; - - if (type == DHCP_REQUEST) { - *p++ = DHCP_MAXMESSAGESIZE; - *p++ = 2; - sz = get_mtu (iface->name); - if (sz < MTU_MIN) { - if (set_mtu (iface->name, MTU_MIN) == 0) - sz = MTU_MIN; - } - sz = htons (sz); - memcpy (p, &sz, 2); - p += 2; - } - - *p++ = DHCP_CLIENTID; - *p++ = iface->clientid_len; - memcpy (p, iface->clientid, iface->clientid_len); - p+= iface->clientid_len; - - if (type != DHCP_DECLINE && type != DHCP_RELEASE) { - if (options->userclass_len > 0) { - *p++ = DHCP_USERCLASS; - *p++ = options->userclass_len; - memcpy (p, &options->userclass, options->userclass_len); - p += options->userclass_len; - } - - if (*options->classid > 0) { - *p++ = DHCP_CLASSID; - *p++ = l = strlen (options->classid); - memcpy (p, options->classid, l); - p += l; - } - } - - if (type == DHCP_DISCOVER || type == DHCP_REQUEST) { -#define PUTADDR(_type, _val) { \ - *p++ = _type; \ - *p++ = 4; \ - memcpy (p, &_val.s_addr, 4); \ - p += 4; \ -} - if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) - logger (LOG_ERR, - "cannot request a link local address"); - else { - if (dhcp->address.s_addr && - dhcp->address.s_addr != - iface->previous_address.s_addr) - { - PUTADDR (DHCP_ADDRESS, dhcp->address); - if (dhcp->serveraddress.s_addr) - PUTADDR (DHCP_SERVERIDENTIFIER, - dhcp->serveraddress); - } - } -#undef PUTADDR - - if (options->leasetime != 0) { - *p++ = DHCP_LEASETIME; - *p++ = 4; - ul = htonl (options->leasetime); - memcpy (p, &ul, 4); - p += 4; - } - } - - if (type == DHCP_DISCOVER || - type == DHCP_INFORM || - type == DHCP_REQUEST) - { - if (options->hostname[0]) { - if (options->fqdn == FQDN_DISABLE) { - *p++ = DHCP_HOSTNAME; - *p++ = l = strlen (options->hostname); - memcpy (p, options->hostname, l); - p += l; - } else { - /* Draft IETF DHC-FQDN option (81) */ - *p++ = DHCP_FQDN; - *p++ = (l = strlen (options->hostname)) + 3; - /* Flags: 0000NEOS - * S: 1 => Client requests Server to update - * a RR in DNS as well as PTR - * O: 1 => Server indicates to client that - * DNS has been updated - * E: 1 => Name data is DNS format - * N: 1 => Client requests Server to not - * update DNS - */ - *p++ = options->fqdn & 0x9; - *p++ = 0; /* from server for PTR RR */ - *p++ = 0; /* from server for A RR if S=1 */ - memcpy (p, options->hostname, l); - p += l; - } - } - - *p++ = DHCP_PARAMETERREQUESTLIST; - n_params = p; - *p++ = 0; - /* Only request DNSSERVER in discover to keep the packets small. - * RFC2131 Section 3.5 states that the REQUEST must include the - * list from the DISCOVER message, so I think this is ok. */ - - if (type == DHCP_DISCOVER && ! options->test) - *p++ = DHCP_DNSSERVER; - else { - if (type != DHCP_INFORM) { - *p++ = DHCP_RENEWALTIME; - *p++ = DHCP_REBINDTIME; - } - *p++ = DHCP_NETMASK; - *p++ = DHCP_BROADCAST; - - /* -S means request CSR and MSCSR - * -SS means only request MSCSR incase DHCP message - * is too big */ - if (options->domscsr < 2) - *p++ = DHCP_CSR; - if (options->domscsr > 0) - *p++ = DHCP_MSCSR; - /* RFC 3442 states classless static routes should be - * before routers and static routes as classless static - * routes override them both */ - *p++ = DHCP_STATICROUTE; - *p++ = DHCP_ROUTERS; - *p++ = DHCP_HOSTNAME; - *p++ = DHCP_DNSSEARCH; - *p++ = DHCP_DNSDOMAIN; - *p++ = DHCP_DNSSERVER; -#ifdef ENABLE_NIS - *p++ = DHCP_NISDOMAIN; - *p++ = DHCP_NISSERVER; -#endif -#ifdef ENABLE_NTP - *p++ = DHCP_NTPSERVER; -#endif - *p++ = DHCP_MTU; -#ifdef ENABLE_INFO - *p++ = DHCP_ROOTPATH; - *p++ = DHCP_SIPSERVER; -#endif - } - - *n_params = p - n_params - 1; - } - *p++ = DHCP_END; - -#ifdef BOOTP_MESSAGE_LENTH_MIN - /* Some crappy DHCP servers think they have to obey the BOOTP minimum - * message length. - * They are wrong, but we should still cater for them. */ - while (p - m < BOOTP_MESSAGE_LENTH_MIN) - *p++ = DHCP_PAD; -#endif - - message_length = p - m; - - packet = xzalloc (sizeof (*packet)); - make_dhcp_packet (packet, (unsigned char *) message, message_length, - from, to); - free (message); - - logger (LOG_DEBUG, "sending %s with xid 0x%x", - dhcp_message (type), xid); - retval = send_packet (iface, ETHERTYPE_IP, (unsigned char *) packet, - message_length + - sizeof (packet->ip) + sizeof (packet->udp)); - free (packet); - return (retval); -} - -/* Decode an RFC3397 DNS search order option into a space - * seperated string. Returns length of string (including - * terminating zero) or zero on error. out may be NULL - * to just determine output length. */ -static unsigned int decode_search (const unsigned char *p, int len, char *out) -{ - const unsigned char *r, *q = p; - unsigned int count = 0, l, hops; - - while (q - p < len) { - r = NULL; - hops = 0; - while ((l = *q++)) { - unsigned int label_type = l & 0xc0; - if (label_type == 0x80 || label_type == 0x40) - return 0; - else if (label_type == 0xc0) { /* pointer */ - l = (l & 0x3f) << 8; - l |= *q++; - - /* save source of first jump. */ - if (!r) - r = q; - - hops++; - if (hops > 255) - return 0; - - q = p + l; - if (q - p >= len) - return 0; - } else { - /* straightforward name segment, add with '.' */ - count += l + 1; - if (out) { - memcpy (out, q, l); - out += l; - *out++ = '.'; - } - q += l; - } - } - - /* change last dot to space */ - if (out) - *(out - 1) = ' '; - - if (r) - q = r; - } - - /* change last space to zero terminator */ - if (out) - *(out - 1) = 0; - - return count; -} - -/* Add our classless static routes to the routes variable - * and return the last route set */ -static struct route_head *decode_CSR (const unsigned char *p, int len) -{ - const unsigned char *q = p; - unsigned int cidr; - unsigned int ocets; - struct route_head *routes = NULL; - route_t *route; - - /* Minimum is 5 -first is CIDR and a router length of 4 */ - if (len < 5) - return NULL; - - while (q - p < len) { - if (! routes) { - routes = xmalloc (sizeof (*routes)); - STAILQ_INIT (routes); - } - - route = xzalloc (sizeof (*route)); - - cidr = *q++; - if (cidr > 32) { - logger (LOG_ERR, - "invalid CIDR of %d in classless static route", - cidr); - free_route (routes); - return (NULL); - } - ocets = (cidr + 7) / 8; - - if (ocets > 0) { - memcpy (&route->destination.s_addr, q, (size_t) ocets); - q += ocets; - } - - /* Now enter the netmask */ - if (ocets > 0) { - memset (&route->netmask.s_addr, 255, (size_t) ocets - 1); - memset ((unsigned char *) &route->netmask.s_addr + - (ocets - 1), - (256 - (1 << (32 - cidr) % 8)), 1); - } - - /* Finally, snag the router */ - memcpy (&route->gateway.s_addr, q, 4); - q += 4; - - STAILQ_INSERT_TAIL (routes, route, entries); - } - - return (routes); -} - -void free_dhcp (dhcp_t *dhcp) -{ - if (! dhcp) - return; - - free_route (dhcp->routes); - free (dhcp->hostname); - free_address (dhcp->dnsservers); - free (dhcp->dnsdomain); - free (dhcp->dnssearch); - free_address (dhcp->ntpservers); - free (dhcp->nisdomain); - free_address (dhcp->nisservers); - free (dhcp->rootpath); - free (dhcp->sipservers); - if (dhcp->fqdn) { - free (dhcp->fqdn->name); - free (dhcp->fqdn); - } -} - - -static bool dhcp_add_address (struct address_head **addresses, - const unsigned char *data, - int length) -{ - int i; - address_t *address; - - for (i = 0; i < length; i += 4) { - /* Sanity check */ - if (i + 4 > length) { - logger (LOG_ERR, "invalid address length"); - return (false); - } - - if (*addresses == NULL) { - *addresses = xmalloc (sizeof (**addresses)); - STAILQ_INIT (*addresses); - } - address = xzalloc (sizeof (*address)); - memcpy (&address->address.s_addr, data + i, 4); - STAILQ_INSERT_TAIL (*addresses, address, entries); - } - - return (true); -} - -#ifdef ENABLE_INFO -static char *decode_sipservers (const unsigned char *data, int length) -{ - char *sip = NULL; - char *p; - const char encoding = *data++; - struct in_addr addr; - size_t len; - - length--; - - switch (encoding) { - case 0: - if ((len = decode_search (data, length, NULL)) > 0) { - sip = xmalloc (len); - decode_search (data, length, sip); - } - break; - - case 1: - if (length == 0 || length % 4 != 0) { - logger (LOG_ERR, - "invalid length %d for option 120", - length + 1); - break; - } - len = ((length / 4) * (4 * 4)) + 1; - sip = p = xmalloc (len); - while (length != 0) { - memcpy (&addr.s_addr, data, 4); - data += 4; - p += snprintf (p, len - (p - sip), - "%s ", inet_ntoa (addr)); - length -= 4; - } - *--p = '\0'; - break; - - default: - logger (LOG_ERR, "unknown sip encoding %d", encoding); - break; - } - - return (sip); -} -#endif - -/* This calculates the netmask that we should use for static routes. - * This IS different from the calculation used to calculate the netmask - * for an interface address. */ -static uint32_t route_netmask (uint32_t ip_in) -{ - /* used to be unsigned long - check if error */ - uint32_t p = ntohl (ip_in); - uint32_t t; - - if (IN_CLASSA (p)) - t = ~IN_CLASSA_NET; - else { - if (IN_CLASSB (p)) - t = ~IN_CLASSB_NET; - else { - if (IN_CLASSC (p)) - t = ~IN_CLASSC_NET; - else - t = 0; - } - } - - while (t & p) - t >>= 1; - - return (htonl (~t)); -} - -static struct route_head *decode_routes (const unsigned char *data, int length) -{ - int i; - struct route_head *head = NULL; - route_t *route; - - for (i = 0; i < length; i += 8) { - if (! head) { - head = xmalloc (sizeof (*head)); - STAILQ_INIT (head); - } - route = xzalloc (sizeof (*route)); - memcpy (&route->destination.s_addr, data + i, 4); - memcpy (&route->gateway.s_addr, data + i + 4, 4); - route->netmask.s_addr = - route_netmask (route->destination.s_addr); - STAILQ_INSERT_TAIL (head, route, entries); - } - - return (head); -} - -static struct route_head *decode_routers (const unsigned char *data, int length) -{ - int i; - struct route_head *head = NULL; - route_t *route = NULL; - - for (i = 0; i < length; i += 4) { - if (! head) { - head = xmalloc (sizeof (*head)); - STAILQ_INIT (head); - } - route = xzalloc (sizeof (*route)); - memcpy (&route->gateway.s_addr, data + i, 4); - STAILQ_INSERT_TAIL (head, route, entries); - } - - return (head); -} - -int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message) -{ - const unsigned char *p = message->options; - const unsigned char *end = p; /* Add size later for gcc-3 issue */ - unsigned char option; - unsigned char length; - unsigned int len = 0; - int retval = -1; - struct timeval tv; - struct route_head *routers = NULL; - struct route_head *routes = NULL; - struct route_head *csr = NULL; - struct route_head *mscsr = NULL; - bool in_overload = false; - bool parse_sname = false; - bool parse_file = false; - - end += sizeof (message->options); - - if (gettimeofday (&tv, NULL) == -1) { - logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); - return (-1); - } - - dhcp->address.s_addr = message->yiaddr; - dhcp->leasedfrom = tv.tv_sec; - dhcp->frominfo = false; - dhcp->address.s_addr = message->yiaddr; - strlcpy (dhcp->servername, (char *) message->servername, - sizeof (dhcp->servername)); - -#define LEN_ERR \ - { \ - logger (LOG_ERR, "invalid length %d for option %d", \ - length, option); \ - p += length; \ - continue; \ - } - -parse_start: - while (p < end) { - option = *p++; - if (! option) - continue; - - if (option == DHCP_END) - goto eexit; - - length = *p++; - - if (option != DHCP_PAD && length == 0) { - logger (LOG_ERR, "option %d has zero length", option); - retval = -1; - goto eexit; - } - - if (p + length >= end) { - logger (LOG_ERR, "dhcp option exceeds message length"); - retval = -1; - goto eexit; - } - - switch (option) { - case DHCP_MESSAGETYPE: - retval = (int) *p; - p += length; - continue; - - default: - if (length == 0) { - logger (LOG_DEBUG, - "option %d has zero length, skipping", - option); - continue; - } - } - -#define LENGTH(_length) \ - if (length != _length) \ - LEN_ERR; -#define MIN_LENGTH(_length) \ - if (length < _length) \ - LEN_ERR; -#define MULT_LENGTH(_mult) \ - if (length % _mult != 0) \ - LEN_ERR; -#define GET_UINT8(_val) \ - LENGTH (sizeof (uint8_t)); \ - memcpy (&_val, p, sizeof (uint8_t)); -#define GET_UINT16(_val) \ - LENGTH (sizeof (uint16_t)); \ - memcpy (&_val, p, sizeof (uint16_t)); -#define GET_UINT32(_val) \ - LENGTH (sizeof (uint32_t)); \ - memcpy (&_val, p, sizeof (uint32_t)); -#define GET_UINT16_H(_val) \ - GET_UINT16 (_val); \ - _val = ntohs (_val); -#define GET_UINT32_H(_val) \ - GET_UINT32 (_val); \ - _val = ntohl (_val); - - switch (option) { - case DHCP_ADDRESS: - GET_UINT32 (dhcp->address.s_addr); - break; - case DHCP_NETMASK: - GET_UINT32 (dhcp->netmask.s_addr); - break; - case DHCP_BROADCAST: - GET_UINT32 (dhcp->broadcast.s_addr); - break; - case DHCP_SERVERIDENTIFIER: - GET_UINT32 (dhcp->serveraddress.s_addr); - break; - case DHCP_LEASETIME: - GET_UINT32_H (dhcp->leasetime); - break; - case DHCP_RENEWALTIME: - GET_UINT32_H (dhcp->renewaltime); - break; - case DHCP_REBINDTIME: - GET_UINT32_H (dhcp->rebindtime); - break; - case DHCP_MTU: - GET_UINT16_H (dhcp->mtu); - /* Minimum legal mtu is 68 accoridng to - * RFC 2132. In practise it's 576 which is the - * minimum maximum message size. */ - if (dhcp->mtu < MTU_MIN) { - logger (LOG_DEBUG, - "MTU %d is too low, minimum is %d; ignoring", - dhcp->mtu, MTU_MIN); - dhcp->mtu = 0; - } - break; - -#undef GET_UINT32_H -#undef GET_UINT32 -#undef GET_UINT16_H -#undef GET_UINT16 -#undef GET_UINT8 - -#define GETSTR(_var) { \ - MIN_LENGTH (sizeof (char)); \ - if (_var) free (_var); \ - _var = xmalloc ((size_t) length + 1); \ - memcpy (_var, p, (size_t) length); \ - memset (_var + length, 0, 1); \ -} - case DHCP_HOSTNAME: - GETSTR (dhcp->hostname); - break; - case DHCP_DNSDOMAIN: - GETSTR (dhcp->dnsdomain); - break; - case DHCP_MESSAGE: - GETSTR (dhcp->message); - break; -#ifdef ENABLE_INFO - case DHCP_ROOTPATH: - GETSTR (dhcp->rootpath); - break; -#endif -#ifdef ENABLE_NIS - case DHCP_NISDOMAIN: - GETSTR (dhcp->nisdomain); - break; -#endif -#undef GETSTR - -#define GETADDR(_var) \ - MULT_LENGTH (4); \ - if (! dhcp_add_address (&_var, p, length)) \ - { \ - retval = -1; \ - goto eexit; \ - } - case DHCP_DNSSERVER: - GETADDR (dhcp->dnsservers); - break; -#ifdef ENABLE_NTP - case DHCP_NTPSERVER: - GETADDR (dhcp->ntpservers); - break; -#endif -#ifdef ENABLE_NIS - case DHCP_NISSERVER: - GETADDR (dhcp->nisservers); - break; -#endif -#undef GETADDR - - case DHCP_DNSSEARCH: - MIN_LENGTH (1); - free (dhcp->dnssearch); - len = decode_search (p, length, NULL); - if (len > 0) { - dhcp->dnssearch = xmalloc (len); - decode_search (p, length, - dhcp->dnssearch); - } - break; - - case DHCP_CSR: - MIN_LENGTH (5); - free_route (csr); - csr = decode_CSR (p, length); - break; - - case DHCP_MSCSR: - MIN_LENGTH (5); - free_route (mscsr); - mscsr = decode_CSR (p, length); - break; - -#ifdef ENABLE_INFO - case DHCP_SIPSERVER: - free (dhcp->sipservers); - dhcp->sipservers = decode_sipservers (p,length); - break; -#endif - - case DHCP_STATICROUTE: - MULT_LENGTH (8); - free_route (routes); - routes = decode_routes (p, length); - break; - - case DHCP_ROUTERS: - MULT_LENGTH (4); - free_route (routers); - routers = decode_routers (p, length); - break; - - case DHCP_OPTIONSOVERLOADED: - LENGTH (1); - /* The overloaded option in an overloaded option - * should be ignored, overwise we may get an - * infinite loop */ - if (! in_overload) { - if (*p & 1) - parse_file = true; - if (*p & 2) - parse_sname = true; - } - break; - - case DHCP_FQDN: - /* We ignore replies about FQDN */ - break; - -#undef LENGTH -#undef MIN_LENGTH -#undef MULT_LENGTH - - default: - logger (LOG_DEBUG, - "no facility to parse DHCP code %u", - option); - break; - } - - p += length; - } - -eexit: - /* We may have options overloaded, so go back and grab them */ - if (parse_file) { - parse_file = false; - p = message->bootfile; - end = p + sizeof (message->bootfile); - in_overload = true; - goto parse_start; - } else if (parse_sname) { - parse_sname = false; - p = message->servername; - end = p + sizeof (message->servername); - memset (dhcp->servername, 0, sizeof (dhcp->servername)); - in_overload = true; - goto parse_start; - } - - /* Fill in any missing fields */ - if (! dhcp->netmask.s_addr) - dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); - if (! dhcp->broadcast.s_addr) - dhcp->broadcast.s_addr = dhcp->address.s_addr | - ~dhcp->netmask.s_addr; - - /* If we have classess static routes then we discard - * static routes and routers according to RFC 3442 */ - if (csr) { - dhcp->routes = csr; - free_route (mscsr); - free_route (routers); - free_route (routes); - } else if (mscsr) { - dhcp->routes = mscsr; - free_route (routers); - free_route (routes); - } else { - /* Ensure that we apply static routes before routers */ - if (! routes) - routes = routers; - else if (routers) - STAILQ_CONCAT (routes, routers); - dhcp->routes = routes; - } - - return (retval); -} diff --git a/customdhcpcd/src/dhcp.h b/customdhcpcd/src/dhcp.h deleted file mode 100644 index ef97b75..0000000 --- a/customdhcpcd/src/dhcp.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef DHCP_H -#define DHCP_H - -#include -#include -#include -#include -#include - -#include "dhcpcd.h" -#include "interface.h" - -/* Max MTU - defines dhcp option length */ -#define MTU_MAX 1500 -#define MTU_MIN 576 - -/* UDP port numbers for DHCP */ -#define DHCP_SERVER_PORT 67 -#define DHCP_CLIENT_PORT 68 - -#define MAGIC_COOKIE 0x63825363 -#define BROADCAST_FLAG 0x8000 - -/* DHCP message OP code */ -#define DHCP_BOOTREQUEST 1 -#define DHCP_BOOTREPLY 2 - -/* DHCP message type */ -#define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 -#define DHCP_ACK 5 -#define DHCP_NAK 6 -#define DHCP_RELEASE 7 -#define DHCP_INFORM 8 - -/* DHCP options */ -enum DHCP_OPTIONS -{ - DHCP_PAD = 0, - DHCP_NETMASK = 1, - DHCP_TIMEROFFSET = 2, - DHCP_ROUTERS = 3, - DHCP_TIMESERVER = 4, - DHCP_NAMESERVER = 5, - DHCP_DNSSERVER = 6, - DHCP_LOGSERVER = 7, - DHCP_COOKIESERVER = 8, - DHCP_HOSTNAME = 12, - DHCP_DNSDOMAIN = 15, - DHCP_ROOTPATH = 17, - DHCP_DEFAULTIPTTL = 23, - DHCP_MTU = 26, - DHCP_BROADCAST = 28, - DHCP_MASKDISCOVERY = 29, - DHCP_ROUTERDISCOVERY = 31, - DHCP_STATICROUTE = 33, - DHCP_NISDOMAIN = 40, - DHCP_NISSERVER = 41, - DHCP_NTPSERVER = 42, - DHCP_ADDRESS = 50, - DHCP_LEASETIME = 51, - DHCP_OPTIONSOVERLOADED = 52, - DHCP_MESSAGETYPE = 53, - DHCP_SERVERIDENTIFIER = 54, - DHCP_PARAMETERREQUESTLIST = 55, - DHCP_MESSAGE = 56, - DHCP_MAXMESSAGESIZE = 57, - DHCP_RENEWALTIME = 58, - DHCP_REBINDTIME = 59, - DHCP_CLASSID = 60, - DHCP_CLIENTID = 61, - DHCP_USERCLASS = 77, /* RFC 3004 */ - DHCP_FQDN = 81, - DHCP_DNSSEARCH = 119, /* RFC 3397 */ - DHCP_SIPSERVER = 120, /* RFC 3361 */ - DHCP_CSR = 121, /* RFC 3442 */ - DHCP_MSCSR = 249, /* MS code for RFC 3442 */ - DHCP_END = 255 -}; - -/* SetFQDNHostName values - lsnybble used in flags - * byte (see buildmsg.c), hsnybble to create order - * and to allow 0x00 to mean disable - */ -enum FQQN { - FQDN_DISABLE = 0x00, - FQDN_NONE = 0x18, - FQDN_PTR = 0x20, - FQDN_BOTH = 0x31 -}; - -typedef struct fqdn_t -{ - uint8_t flags; - uint8_t r1; - uint8_t r2; - char *name; -} fqdn_t; - -typedef struct dhcp_t -{ - char version[11]; - - struct in_addr serveraddress; - char serverhw[IF_NAMESIZE]; - char servername[64]; - - struct in_addr address; - struct in_addr netmask; - struct in_addr broadcast; - unsigned short mtu; - - uint32_t leasedfrom; - uint32_t leasetime; - uint32_t renewaltime; - uint32_t rebindtime; - - struct route_head *routes; - - char *hostname; - fqdn_t *fqdn; - - struct address_head *dnsservers; - char *dnsdomain; - char *dnssearch; - - struct address_head *ntpservers; - - struct address_head *nisservers; - char *nisdomain; - - char *sipservers; - - char *message; - char *rootpath; - - bool frominfo; -} dhcp_t; - -/* Sizes for DHCP options */ -#define DHCP_CHADDR_LEN 16 -#define SERVERNAME_LEN 64 -#define BOOTFILE_LEN 128 -#define DHCP_UDP_LEN (20 + 8) -#define DHCP_BASE_LEN (4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4) -#define DHCP_RESERVE_LEN (4 + 4 + 4 + 4 + 2) -#define DHCP_FIXED_LEN (DHCP_BASE_LEN + DHCP_CHADDR_LEN + \ - + SERVERNAME_LEN + BOOTFILE_LEN) -#define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \ - - DHCP_RESERVE_LEN) - -/* Some crappy DHCP servers require the BOOTP minimum length */ -#define BOOTP_MESSAGE_LENTH_MIN 300 - -typedef struct dhcpmessage_t -{ - unsigned char op; /* message type */ - unsigned char hwtype; /* hardware address type */ - unsigned char hwlen; /* hardware address length */ - unsigned char hwopcount; /* should be zero in client message */ - uint32_t xid; /* transaction id */ - uint16_t secs; /* elapsed time in sec. from boot */ - uint16_t flags; - uint32_t ciaddr; /* (previously allocated) client IP */ - uint32_t yiaddr; /* 'your' client IP address */ - uint32_t siaddr; /* should be zero in client's messages */ - uint32_t giaddr; /* should be zero in client's messages */ - unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ - unsigned char servername[SERVERNAME_LEN]; /* server host name */ - unsigned char bootfile[BOOTFILE_LEN]; /* boot file name */ - uint32_t cookie; - unsigned char options[DHCP_OPTION_LEN]; /* message options - cookie */ -} dhcpmessage_t; - -struct udp_dhcp_packet -{ - struct ip ip; - struct udphdr udp; - dhcpmessage_t dhcp; -}; - -ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp, - uint32_t xid, char type, const options_t *options); -void free_dhcp (dhcp_t *dhcp); -int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message); -#endif diff --git a/customdhcpcd/src/dhcpcd.c b/customdhcpcd/src/dhcpcd.c deleted file mode 100644 index d0ad5e7..0000000 --- a/customdhcpcd/src/dhcpcd.c +++ /dev/null @@ -1,671 +0,0 @@ - /* dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -const char copyright[] = "Copyright (c) 2006-2008 Roy Marples"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "client.h" -#include "dhcpcd.h" -#include "dhcp.h" -#include "interface.h" -#include "logger.h" -#include "socket.h" -#include "version.h" - -#include "logwriter.h" - -static int doversion = 0; -static int dohelp = 0; -#define EXTRA_OPTS -static const struct option longopts[] = { - {"arp", no_argument, NULL, 'a'}, - {"script", required_argument, NULL, 'c'}, - {"debug", no_argument, NULL, 'd'}, - {"hostname", optional_argument, NULL, 'h'}, - {"classid", optional_argument, NULL, 'i'}, - {"release", no_argument, NULL, 'k'}, - {"leasetime", required_argument, NULL, 'l'}, - {"metric", required_argument, NULL, 'm'}, - {"renew", no_argument, NULL, 'n'}, - {"persistent", no_argument, NULL, 'p'}, - {"qtsocketaddress", required_argument, NULL, 'q'}, - {"inform", optional_argument, NULL, 's'}, - {"request", optional_argument, NULL, 'r'}, - {"timeout", required_argument, NULL, 't'}, - {"userclass", required_argument, NULL, 'u'}, - {"exit", no_argument, NULL, 'x'}, - {"lastlease", no_argument, NULL, 'E'}, - {"fqdn", required_argument, NULL, 'F'}, - {"nogateway", no_argument, NULL, 'G'}, - {"sethostname", no_argument, NULL, 'H'}, - {"clientid", optional_argument, NULL, 'I'}, - {"noipv4ll", no_argument, NULL, 'L'}, - {"nomtu", no_argument, NULL, 'M'}, - {"nontp", no_argument, NULL, 'N'}, - {"nodns", no_argument, NULL, 'R'}, - {"msscr", no_argument, NULL, 'S'}, - {"test", no_argument, NULL, 'T'}, - {"nonis", no_argument, NULL, 'Y'}, - {"help", no_argument, &dohelp, 1}, - {"version", no_argument, &doversion, 1}, -#ifdef THERE_IS_NO_FORK - {"daemonised", no_argument, NULL, 'f'}, - {"skiproutes", required_argument, NULL, 'g'}, -#endif - {NULL, 0, NULL, 0} -}; - -#ifdef THERE_IS_NO_FORK -char dhcpcd[PATH_MAX]; -char **dhcpcd_argv = NULL; -int dhcpcd_argc = 0; -char *dhcpcd_skiproutes = NULL; -#undef EXTRA_OPTS -#define EXTRA_OPTS "fg:" -#endif - -static int atoint (const char *s) -{ - char *t; - long n; - - errno = 0; - n = strtol (s, &t, 0); - if ((errno != 0 && n == 0) || s == t || - (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN))) - { - logger (LOG_ERR, "`%s' out of range", s); - return (-1); - } - - return ((int) n); -} - -static pid_t read_pid (const char *pidfile) -{ - FILE *fp; - pid_t pid = 0; - - if ((fp = fopen (pidfile, "r")) == NULL) { - errno = ENOENT; - return 0; - } - - fscanf (fp, "%d", &pid); - fclose (fp); - - - return (pid); -} - -static void usage (void) -{ - printf ("usage: "PACKAGE" [-adknpEGHMNRSTY] [-c script] [-h hostname] [-i classID]\n" - " [-l leasetime] [-m metric] [-r ipaddress] [-s ipaddress]\n" - " [-t timeout] [-u userclass] [-F none | ptr | both]\n" - " [-I clientID] [-q qtsocketaddress] \n"); -} - - -int main (int argc, char **argv) -{ - options_t *options; - int userclasses = 0; - int opt; - int option_index = 0; - char *prefix; - pid_t pid; - int debug = 0; - int i; - int pidfd = -1; - int sig = 0; - int retval = EXIT_FAILURE; - - /* Close any un-needed fd's */ - for (i = getdtablesize() - 1; i >= 3; --i) - close (i); - - openlog (PACKAGE, LOG_PID, LOG_LOCAL0); - - options = xzalloc (sizeof (*options)); - options->script = (char *) DEFAULT_SCRIPT; - snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", - PACKAGE, VERSION); - - options->doarp = true; - options->dodns = true; - options->domtu = true; - options->donis = true; - options->dontp = true; - options->dogateway = true; - options->daemonise = true; - options->doinform = false; - options->doipv4ll = true; - options->doduid = true; - options->timeout = DEFAULT_TIMEOUT; - /* added by Niklas Goby, additional field, storing the socket address path for - * communicating with Qt "server" - * defined in dhcpcd.h */ - strcpy(options->qtsocketaddress, DEFAULT_QTSOCKETADDRESS); - - gethostname (options->hostname, sizeof (options->hostname)); - if (strcmp (options->hostname, "(none)") == 0 || - strcmp (options->hostname, "localhost") == 0) - memset (options->hostname, 0, sizeof (options->hostname)); - - - /* Don't set any optional arguments here so we retain POSIX - * compatibility with getopt */ - while ((opt = getopt_long(argc, argv, EXTRA_OPTS - "c:dh:i:kl:m:npq:r:s:t:u:xAEF:GHI:LMNRSTY", - longopts, &option_index)) != -1) - { - switch (opt) { - case 0: - if (longopts[option_index].flag) - break; - logger (LOG_ERR, - "option `%s' should set a flag", - longopts[option_index].name); - goto abort; - case 'c': - options->script = optarg; - break; - case 'd': - debug++; - switch (debug) { - case 1: - setloglevel (LOG_DEBUG); - break; - case 2: - options->daemonise = false; - break; - } - break; - #ifdef THERE_IS_NO_FORK - case 'f': - options->daemonised = true; - close_fds (); - break; - case 'g': - dhcpcd_skiproutes = xstrdup (optarg); - break; - #endif - case 'h': - if (! optarg) - *options->hostname = '\0'; - else if (strlen (optarg) > MAXHOSTNAMELEN) { - logger (LOG_ERR, - "`%s' too long for HostName string, max is %d", - optarg, MAXHOSTNAMELEN); - goto abort; - } else - strlcpy (options->hostname, optarg, - sizeof (options->hostname)); - break; - case 'i': - if (! optarg) { - *options->classid = '\0'; - } else if (strlen (optarg) > CLASS_ID_MAX_LEN) { - logger (LOG_ERR, - "`%s' too long for ClassID string, max is %d", - optarg, CLASS_ID_MAX_LEN); - goto abort; - } else - strlcpy (options->classid, optarg, - sizeof (options->classid)); - break; - case 'k': - sig = SIGHUP; - break; - case 'l': - if (*optarg == '-') { - logger (LOG_ERR, - "leasetime must be a positive value"); - goto abort; - } - errno = 0; - options->leasetime = (uint32_t) strtol (optarg, NULL, 0); - if (errno == EINVAL || errno == ERANGE) { - logger (LOG_ERR, "`%s' out of range", optarg); - goto abort; - } - break; - case 'm': - options->metric = atoint (optarg); - if (options->metric < 0) { - logger (LOG_ERR, - "metric must be a positive value"); - goto abort; - } - break; - case 'n': - sig = SIGALRM; - break; - case 'p': - options->persistent = true; - break; - case 'q': - if (strlen(optarg) > QTSOCKETADDRESSLENGTH) { - logger(LOG_ERR, "`%s' too long for an socket address path (max=%d)", - optarg, QTSOCKETADDRESSLENGTH); - goto abort; - } - strlcpy(options->qtsocketaddress, optarg, sizeof(options->qtsocketaddress)); - break; - case 's': - options->doinform = true; - options->doarp = false; - if (! optarg || strlen (optarg) == 0) { - options->request_address.s_addr = 0; - break; - } else { - char *slash = strchr (optarg, '/'); - if (slash) { - int cidr; - /* nullify the slash, so the -r option can read the - * address */ - *slash++ = '\0'; - if (sscanf (slash, "%d", &cidr) != 1 || - inet_cidrtoaddr (cidr, &options->request_netmask) != 0) { - logger (LOG_ERR, "`%s' is not a valid CIDR", slash); - goto abort; - } - } - } - /* FALLTHROUGH */ - case 'r': - if (! options->doinform) - options->dorequest = true; - if (strlen (optarg) > 0 && - ! inet_aton (optarg, &options->request_address)) - { - logger (LOG_ERR, "`%s' is not a valid IP address", optarg); - goto abort; - } - break; - case 't': - options->timeout = atoint (optarg); - if (options->timeout < 0) { - logger (LOG_ERR, "timeout must be a positive value"); - goto abort; - } - break; - case 'u': - { - int offset = 0; - for (i = 0; i < userclasses; i++) - offset += (int) options->userclass[offset] + 1; - if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) { - logger (LOG_ERR, "userclass overrun, max is %d", - USERCLASS_MAX_LEN); - goto abort; - } - userclasses++; - memcpy (options->userclass + offset + 1 , optarg, strlen (optarg)); - options->userclass[offset] = strlen (optarg); - options->userclass_len += (strlen (optarg)) + 1; - } - break; - case 'x': - sig = SIGTERM; - break; - case 'A': - #ifndef ENABLE_ARP - logger (LOG_ERR, - "arp not compiled into dhcpcd"); - goto abort; - #endif - options->doarp = false; - break; - case 'E': - #ifndef ENABLE_INFO - logger (LOG_ERR, - "info not compiled into dhcpcd"); - goto abort; - #endif - options->dolastlease = true; - break; - case 'F': - if (strncmp (optarg, "none", strlen (optarg)) == 0) - options->fqdn = FQDN_NONE; - else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) - options->fqdn = FQDN_PTR; - else if (strncmp (optarg, "both", strlen (optarg)) == 0) - options->fqdn = FQDN_BOTH; - else { - logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); - goto abort; - } - break; - case 'G': - options->dogateway = false; - break; - case 'H': - options->dohostname++; - break; - case 'I': - if (optarg) { - if (strlen (optarg) > CLIENT_ID_MAX_LEN) { - logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", - optarg, CLIENT_ID_MAX_LEN); - goto abort; - } - if (strlcpy (options->clientid, optarg, - sizeof (options->clientid)) == 0) - /* empty string disabled duid */ - options->doduid = false; - - } else { - memset (options->clientid, 0, sizeof (options->clientid)); - options->doduid = false; - } - break; - case 'L': - options->doipv4ll = false; - break; - case 'M': - options->domtu = false; - break; - case 'N': - options->dontp = false; - break; - case 'R': - options->dodns = false; - break; - case 'S': - options->domscsr++; - break; - case 'T': - #ifndef ENABLE_INFO - logger (LOG_ERR, "info support not compiled into dhcpcd"); - goto abort; - #endif - options->test = true; - options->persistent = true; - break; - case 'Y': - options->donis = false; - break; - case '?': - usage (); - goto abort; - default: - usage (); - goto abort; - } - } - if (doversion) { - printf (""PACKAGE" "VERSION"\n"); - printf ("Compile time options:" - #ifdef ENABLE_ARP - " ARP" - #endif - #ifdef ENABLE_DUID - " DUID" - #endif - #ifdef ENABLE_INFO - " INFO" - #endif - #ifdef ENABLE_INFO_COMPAT - " INFO_COMPAT" - #endif - #ifdef ENABLE_IPV4LL - " IPV4LL" - #endif - #ifdef ENABLE_NIS - " NIS" - #endif - #ifdef ENABLE_NTP - " NTP" - #endif - #ifdef SERVICE - " " SERVICE - #endif - #ifdef ENABLE_RESOLVCONF - " RESOLVCONF" - #endif - #ifdef THERE_IS_NO_FORK - " THERE_IS_NO_FORK" - #endif - "\n"); - } - - if (dohelp) - usage (); - - -#ifdef THERE_IS_NO_FORK - dhcpcd_argv = argv; - dhcpcd_argc = argc; - if (! realpath (argv[0], dhcpcd)) { - logger (LOG_ERR, "unable to resolve the path `%s': %s", - argv[0], strerror (errno)); - goto abort; - } -#endif - - /* initializations for the ipc connection to qt*/ - setSocketName(options->qtsocketaddress); - if (initQtLoggerSocket() < 0) { - logger(LOG_ERR, "initialization Qt Logger failed: %s ", strerror (errno)); - goto abort; - } - - - if (optind < argc) { - if (strlen(argv[optind]) > IF_NAMESIZE) { - logger(LOG_ERR, "`%s' too long for an interface name (max=%d)", - argv[optind], IF_NAMESIZE); - goto abort; - } - strlcpy(options->interface, argv[optind], sizeof(options->interface)); - setInterfaceName(options->interface); - } else { - /* If only version was requested then exit now */ - if (doversion || dohelp) { - retval = 0; - goto abort; - } - - logger(LOG_ERR, "no interface specified"); - setInterfaceName("no_if"); - goto abort; - } - - if (strchr(options->hostname, '.')) { - if (options->fqdn == FQDN_DISABLE) - options->fqdn = FQDN_BOTH; - } else - options->fqdn = FQDN_DISABLE; - - if (options->request_address.s_addr == 0 && options->doinform) { - if ((options->request_address.s_addr = get_address(options->interface)) - != 0) - options->keep_address = true; - } - - if (IN_LINKLOCAL (ntohl (options->request_address.s_addr))) { - logger (LOG_ERR, - "you are not allowed to request a link local address"); - logToQt(LOG_ERR, -1, "you are not allowed to request a link local address"); - goto abort; - } - - if (geteuid ()) { - logger (LOG_WARNING, PACKAGE " will not work correctly unless" - " run as root"); - } - - prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3)); - snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface); - setlogprefix (prefix); - snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE, - options->interface); - free (prefix); - - chdir ("/"); - umask (022); - - if (mkdir (INFODIR, S_IRUSR | S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP - | S_IROTH | S_IXOTH) && errno != EEXIST) - { - logger (LOG_ERR, - "mkdir(\"%s\",0): %s\n", INFODIR, strerror (errno)); - goto abort; - } - - if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP - | S_IROTH | S_IXOTH) && errno != EEXIST) - { - logger (LOG_ERR, - "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); - goto abort; - } - - if (options->test) { - if (options->dorequest || options->doinform) { - logger (LOG_ERR, - "cannot test with --inform or --request"); - goto abort; - } - - if (options->dolastlease) { - logger (LOG_ERR, "cannot test with --lastlease"); - goto abort; - } - - if (sig != 0) { - logger (LOG_ERR, - "cannot test with --release or --renew"); - goto abort; - } - } - - if (sig != 0) { - int killed = -1; - pid = read_pid (options->pidfile); - if (pid != 0) - logger (LOG_INFO, "sending signal %d to pid %d", - sig, pid); - - if (! pid || (killed = kill (pid, sig))) - logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, - ""PACKAGE" not running"); - - if (pid != 0 && (sig != SIGALRM || killed != 0)) - unlink (options->pidfile); - - if (killed == 0) { - retval = EXIT_SUCCESS; - goto abort; - } - - if (sig != SIGALRM) - goto abort; - } - - if (! options->test && ! options->daemonised) { - if ((pid = read_pid (options->pidfile)) > 0 && - kill (pid, 0) == 0) - { - logger (LOG_ERR, ""PACKAGE - " already running on pid %d (%s)", - pid, options->pidfile); - goto abort; - } - - pidfd = open (options->pidfile, - O_WRONLY | O_CREAT | O_NONBLOCK, 0664); - if (pidfd == -1) { - logger (LOG_ERR, "open `%s': %s", - options->pidfile, strerror (errno)); - goto abort; - } - - /* Lock the file so that only one instance of dhcpcd runs - * on an interface */ - if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) { - logger (LOG_ERR, "flock `%s': %s", - options->pidfile, strerror (errno)); - goto abort; - } - - /* dhcpcd.sh should not interhit this fd */ - if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 || - fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1) - logger (LOG_ERR, "fcntl: %s", strerror (errno)); - - writepid (pidfd, getpid ()); - logger (LOG_INFO, PACKAGE " " VERSION " starting"); - } - - /* Seed random */ - srandomdev (); - - /* Massage our filters per platform */ - setup_packet_filters (); - - /* dhcp_run : defined in client.c */ - if (dhcp_run (options, &pidfd) == 0) - retval = EXIT_SUCCESS; - -abort: - /* If we didn't daemonise then we need to punt the pidfile now */ - if (pidfd > -1) { - close (pidfd); - unlink (options->pidfile); - } - - free (options); - -#ifdef THERE_IS_NO_FORK - /* There may have been an error before the dhcp_run function - * clears this, so just do it here to be safe */ - free (dhcpcd_skiproutes); -#endif - - logger (LOG_INFO, "exiting"); - logToQt(LOG_INFO, DHCPCD_EXIT, "exiting due abort"); - closeQtLoggerSocket(); - exit (retval); - /* NOTREACHED */ -} diff --git a/customdhcpcd/src/dhcpcd.h b/customdhcpcd/src/dhcpcd.h deleted file mode 100644 index c8df616..0000000 --- a/customdhcpcd/src/dhcpcd.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef DHCPCD_H -#define DHCPCD_H - -#include -#include -#include -#include -#include -#include - -#include "common.h" - -#include "../../common/fbgui.h" - -#define DEFAULT_TIMEOUT 20 -#define DEFAULT_LEASETIME 3600 /* 1 hour */ - -/* added by Niklas Goby, additional field, storing the socket address path for - * communicating with Qt "server" */ - - -#define QTSOCKETADDRESSLENGTH 255 - -#define CLASS_ID_MAX_LEN 48 -#define CLIENT_ID_MAX_LEN 48 -#define USERCLASS_MAX_LEN 255 - -#ifdef THERE_IS_NO_FORK -extern char dhcpcd[PATH_MAX]; -extern char **dhcpcd_argv; -extern int dhcpcd_argc; -extern char *dhcpcd_skiproutes; -#endif - -typedef struct options_t { - /* added by Niklas Goby, additional field, storing the socket address path for - * communicating with Qt "server" */ - char qtsocketaddress[QTSOCKETADDRESSLENGTH]; - /*----*/ - char interface[IF_NAMESIZE]; - char hostname[MAXHOSTNAMELEN]; - int fqdn; - char classid[CLASS_ID_MAX_LEN]; - char clientid[CLIENT_ID_MAX_LEN]; - char userclass[USERCLASS_MAX_LEN]; - size_t userclass_len; - uint32_t leasetime; - time_t timeout; - int metric; - - bool doarp; - bool dodns; - bool dodomainname; - bool dogateway; - int dohostname; - bool domtu; - bool donis; - bool dontp; - bool dolastlease; - bool doinform; - bool dorequest; - bool doipv4ll; - bool doduid; - int domscsr; - - struct in_addr request_address; - struct in_addr request_netmask; - - bool persistent; - bool keep_address; - bool daemonise; - bool daemonised; - bool test; - - char *script; - char pidfile[PATH_MAX]; -} options_t; - -int nd_main (char *ifname); - -#endif diff --git a/customdhcpcd/src/dhcpcd.sh b/customdhcpcd/src/dhcpcd.sh deleted file mode 100644 index 8c86aac..0000000 --- a/customdhcpcd/src/dhcpcd.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh -# -# This is a sample /etc/dhcpcd.sh script. -# /etc/dhcpcd.sh script is executed by dhcpcd daemon -# any time it configures or shuts down interface. -# The following parameters are passed to dhcpcd.exe script: -# $1 = HostInfoFilePath, e.g "/var/lib/dhcpcd/dhcpcd-eth0.info" -# $2 = "up" if interface has been configured with the same -# IP address as before reboot; -# $2 = "down" if interface has been shut down; -# $2 = "new" if interface has been configured with new IP address; -# -# Sanity checks - -if [ $# -lt 2 ]; then - logger -s -p local0.err -t dhcpcd.sh "wrong usage" - exit 1 -fi - -hostinfo="$1" -state="$2" - -# Reading HostInfo file for configuration parameters -[ -e "${hostinfo}" ] && . "${hostinfo}" - -case "${state}" in - up) - logger -s -p local0.info -t dhcpcd.sh \ - "interface ${INTERFACE} has been configured with old IP=${IPADDR}" - # Put your code here for when the interface has been brought up with an - # old IP address here - ;; - - new) - logger -s -p local0.info -t dhcpcd.sh \ - "interface ${INTERFACE} has been configured with new IP=${IPADDR}" - # Put your code here for when the interface has been brought up with a - # new IP address - ;; - - down) logger -s -p local0.info -t dhcpcd.sh \ - "interface ${INTERFACE} has been brought down" - # Put your code here for the when the interface has been shut down - ;; -esac -exit 0 diff --git a/customdhcpcd/src/discover.c b/customdhcpcd/src/discover.c deleted file mode 100644 index eae7b0a..0000000 --- a/customdhcpcd/src/discover.c +++ /dev/null @@ -1,7 +0,0 @@ -/* - * discover.c - * - * Created on: Jul 7, 2011 - * Author: niklas - */ - diff --git a/customdhcpcd/src/discover.h b/customdhcpcd/src/discover.h deleted file mode 100644 index 1f4918d..0000000 --- a/customdhcpcd/src/discover.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * discover.h - * - * Created on: Jul 7, 2011 - * Author: niklas - */ - -#ifndef DISCOVER_H_ -#define DISCOVER_H_ - - -#endif /* DISCOVER_H_ */ diff --git a/customdhcpcd/src/duid.c b/customdhcpcd/src/duid.c deleted file mode 100644 index e4dd83b..0000000 --- a/customdhcpcd/src/duid.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "common.h" -#include "duid.h" -#include "logger.h" - -#ifdef ENABLE_DUID - -#define THIRTY_YEARS_IN_SECONDS 946707779 - -size_t get_duid (unsigned char *duid, const interface_t *iface) -{ - FILE *f; - uint16_t type = 0; - uint16_t hw = 0; - uint32_t ul; - time_t t; - int x = 0; - unsigned char *p = duid; - size_t len = 0; - - if (! iface) - return (0); - - /* If we already have a DUID then use it as it's never supposed - * to change once we have one even if the interfaces do */ - if ((f = fopen (DUIDFILE, "r"))) { - char *line = get_line (f); - if (line) { - len = hwaddr_aton (NULL, line); - if (len && len <= DUID_LEN) - hwaddr_aton (duid, line); - free (line); - } - fclose (f); - if (len) - return (len); - } else { - if (errno != ENOENT) { - logger (LOG_ERR, "fopen `%s': %s", - DUIDFILE, strerror (errno)); - return (0); - } - } - - /* No file? OK, lets make one based on our interface */ - type = htons (1); /* DUI-D-LLT */ - memcpy (p, &type, 2); - p += 2; - - hw = htons (iface->family); - memcpy (p, &hw, 2); - p += 2; - - /* time returns seconds from jan 1 1970, but DUID-LLT is - * seconds from jan 1 2000 modulo 2^32 */ - t = time (NULL) - THIRTY_YEARS_IN_SECONDS; - ul = htonl (t & 0xffffffff); - memcpy (p, &ul, 4); - p += 4; - - /* Finally, add the MAC address of the interface */ - memcpy (p, iface->hwaddr, iface->hwlen); - p += iface->hwlen; - - len = p - duid; - - if (! (f = fopen (DUIDFILE, "w"))) - logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno)); - else { - x = fprintf (f, "%s\n", hwaddr_ntoa (duid, len)); - fclose (f); - } - - /* Failed to write the duid? scrub it, we cannot use it */ - if (x < 1) { - len = 0; - unlink (DUIDFILE); - } - - return (len); -} -#endif diff --git a/customdhcpcd/src/duid.h b/customdhcpcd/src/duid.h deleted file mode 100644 index 1492990..0000000 --- a/customdhcpcd/src/duid.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef DUID_H -#define DUID_H - -#include "config.h" - -#ifdef ENABLE_DUID -#ifndef DUID_LEN -# define DUID_LEN 128 + 2 -#endif - -#include "interface.h" - -size_t get_duid (unsigned char *duid, const interface_t *iface); -#endif -#endif diff --git a/customdhcpcd/src/info.c b/customdhcpcd/src/info.c deleted file mode 100644 index 8369b43..0000000 --- a/customdhcpcd/src/info.c +++ /dev/null @@ -1,472 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include - -#include -#include -#include -#include -#include - -#include "config.h" -#include "common.h" -#include "dhcp.h" -#include "interface.h" -#include "logger.h" -#include "info.h" - -#ifdef ENABLE_INFO - -/* Create a malloced string of cstr, changing ' to '\'' - * so the contents work in a shell */ -static char *cleanmetas (const char *cstr) -{ - const char *p = cstr; - char *new; - char *n; - size_t len; - - if (cstr == NULL || (len = strlen (cstr)) == 0) - return (xstrdup ("")); - - n = new = xmalloc (sizeof (char) * len + 2); - do - if (*p == '\'') { - size_t pos = n - new; - len += 4; - new = xrealloc (new, sizeof (char) * len + 1); - n = new + pos; - *n++ = '\''; - *n++ = '\\'; - *n++ = '\''; - *n++ = '\''; - } else - *n++ = *p; - while (*p++); - - /* Terminate the sucker */ - *n = '\0'; - - return (new); -} - - -static void print_addresses (FILE *f, const struct address_head *addresses) -{ - const address_t *addr; - - STAILQ_FOREACH (addr, addresses, entries) { - fprintf (f, "%s", inet_ntoa (addr->address)); - if (STAILQ_NEXT (addr, entries)) - fprintf (f, " "); - } -} - -static void print_clean (FILE *f, const char *name, const char *value) -{ - char *clean; - - if (! value) - return; - - clean = cleanmetas (value); - fprintf (f, "%s='%s'\n", name, clean); - free (clean); -} - -bool write_info(const interface_t *iface, const dhcp_t *dhcp, - const options_t *options, bool overwrite) -{ - FILE *f; - route_t *route; - struct stat sb; - - if (options->test) - f = stdout; - else { - if (! overwrite && stat (iface->infofile, &sb) == 0) - return (true); - - logger (LOG_DEBUG, "writing %s", iface->infofile); - if ((f = fopen (iface->infofile, "w")) == NULL) { - logger (LOG_ERR, "fopen `%s': %s", - iface->infofile, strerror (errno)); - return (false); - } - } - - if (dhcp->address.s_addr) { - struct in_addr n; - n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; - fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address)); - fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask)); - fprintf (f, "NETWORK='%s'\n", inet_ntoa (n)); - fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast)); - } - if (dhcp->mtu > 0) - fprintf (f, "MTU='%d'\n", dhcp->mtu); - - if (dhcp->routes) { - bool doneone = false; - fprintf (f, "ROUTES='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr != 0) { - if (doneone) - fprintf (f, " "); - fprintf (f, "%s", inet_ntoa (route->destination)); - fprintf (f, ",%s", inet_ntoa (route->netmask)); - fprintf (f, ",%s", inet_ntoa (route->gateway)); - doneone = true; - } - } - fprintf (f, "'\n"); - - doneone = false; - fprintf (f, "GATEWAYS='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr == 0) { - if (doneone) - fprintf (f, " "); - fprintf (f, "%s", inet_ntoa (route->gateway)); - doneone = true; - } - } - fprintf (f, "'\n"); - } - - print_clean (f, "HOSTNAME", dhcp->hostname); - print_clean (f, "DNSDOMAIN", dhcp->dnsdomain); - print_clean (f, "DNSSEARCH", dhcp->dnssearch); - - if (dhcp->dnsservers) { - fprintf (f, "DNSSERVERS='"); - print_addresses (f, dhcp->dnsservers); - fprintf (f, "'\n"); - } - - if (dhcp->fqdn) { - fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags); - fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1); - fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2); - print_clean (f, "FQDNHOSTNAME", dhcp->fqdn->name); - } - - if (dhcp->ntpservers) { - fprintf (f, "NTPSERVERS='"); - print_addresses (f, dhcp->ntpservers); - fprintf (f, "'\n"); - } - - print_clean (f, "NISDOMAIN", dhcp->nisdomain); - if (dhcp->nisservers) { - fprintf (f, "NISSERVERS='"); - print_addresses (f, dhcp->nisservers); - fprintf (f, "'\n"); - } - - print_clean (f, "ROOTPATH", dhcp->rootpath); - print_clean (f, "SIPSERVERS", dhcp->sipservers); - - if (dhcp->serveraddress.s_addr) - fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); - if (dhcp->servername[0]) - print_clean (f, "DHCPSNAME", dhcp->servername); - - if (! options->doinform && dhcp->address.s_addr) { - if (! options->test) - fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom); - fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime); - fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); - fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); - } - print_clean (f, "INTERFACE", iface->name); - print_clean (f, "CLASSID", options->classid); - if (iface->clientid_len > 0) { - fprintf (f, "CLIENTID='%s'\n", - hwaddr_ntoa (iface->clientid, iface->clientid_len)); - } - fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, - iface->hwlen)); - -#ifdef ENABLE_INFO_COMPAT - /* Support the old .info settings if we need to */ - fprintf (f, "\n# dhcpcd-1.x and 2.x compatible variables\n"); - if (dhcp->dnsservers) { - address_t *addr; - - fprintf (f, "DNS='"); - STAILQ_FOREACH (addr, dhcp->dnsservers, entries) { - fprintf (f, "%s", inet_ntoa (addr->address)); - if (STAILQ_NEXT (addr, entries)) - fprintf (f, ","); - } - fprintf (f, "'\n"); - } - - if (dhcp->routes) { - bool doneone = false; - fprintf (f, "GATEWAY='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr == 0) { - if (doneone) - fprintf (f, ","); - fprintf (f, "%s", inet_ntoa (route->gateway)); - doneone = true; - } - } - fprintf (f, "'\n"); - } -#endif - - if (! options->test) - fclose (f); - return (true); -} - -static bool parse_address (struct in_addr *addr, - const char *value, const char *var) -{ - if (inet_aton (value, addr) == 0) { - logger (LOG_ERR, "%s `%s': %s", var, value, - strerror (errno)); - return (false); - } - return (true); -} - -static bool parse_uint (unsigned int *i, - const char *value, const char *var) -{ - if (sscanf (value, "%u", i) != 1) { - logger (LOG_ERR, "%s `%s': not a valid number", - var, value); - return (false); - } - return (true); -} - -static bool parse_ushort (unsigned short *s, - const char *value, const char *var) -{ - if (sscanf (value, "%hu", s) != 1) { - logger (LOG_ERR, "%s `%s': not a valid number", - var, value); - return (false); - } - return (true); -} - -static struct address_head *parse_addresses (char *value, const char *var) -{ - char *token; - char *p = value; - struct address_head *head = NULL; - - while ((token = strsep (&p, " "))) { - address_t *a = xzalloc (sizeof (*a)); - - if (inet_aton (token, &a->address) == 0) { - logger (LOG_ERR, "%s: invalid address `%s'", var, token); - free_address (head); - free (a); - return (NULL); - } - - if (! head) { - head = xmalloc (sizeof (*head)); - STAILQ_INIT (head); - } - STAILQ_INSERT_TAIL (head, a, entries); - } - - return (head); -} - -bool read_info (const interface_t *iface, dhcp_t *dhcp) -{ - FILE *fp; - char *line; - char *var; - char *value; - char *p; - struct stat sb; - - if (stat (iface->infofile, &sb) != 0) { - logger (LOG_ERR, "lease information file `%s' does not exist", - iface->infofile); - return (false); - } - - if (! (fp = fopen (iface->infofile, "r"))) { - logger (LOG_ERR, "fopen `%s': %s", - iface->infofile, strerror (errno)); - return (false); - } - - dhcp->frominfo = true; - - while ((line = get_line (fp))) { - var = line; - - /* Strip leading spaces/tabs */ - while ((*var == ' ') || (*var == '\t')) - var++; - - /* Trim trailing \n */ - p = var + strlen (var) - 1; - if (*p == '\n') - *p = 0; - - /* Skip comments */ - if (*var == '#') - goto next; - - /* If we don't have an equals sign then skip it */ - if (! (p = strchr (var, '='))) - goto next; - - /* Terminate the = so we have two strings */ - *p = 0; - - value = p + 1; - /* Strip leading and trailing quotes if present */ - if (*value == '\'' || *value == '"') - value++; - p = value + strlen (value) - 1; - if (*p == '\'' || *p == '"') - *p = 0; - - /* Don't process null vars or values */ - if (! *var || ! *value) - goto next; - - if (strcmp (var, "IPADDR") == 0) - parse_address (&dhcp->address, value, "IPADDR"); - else if (strcmp (var, "NETMASK") == 0) - parse_address (&dhcp->netmask, value, "NETMASK"); - else if (strcmp (var, "BROADCAST") == 0) - parse_address (&dhcp->broadcast, value, "BROADCAST"); - else if (strcmp (var, "MTU") == 0) - parse_ushort (&dhcp->mtu, value, "MTU"); - else if (strcmp (var, "ROUTES") == 0) { - p = value; - while ((value = strsep (&p, " "))) { - char *pp = value; - char *dest = strsep (&pp, ","); - char *net = strsep (&pp, ","); - char *gate = strsep (&pp, ","); - route_t *route; - - if (! dest || ! net || ! gate) { - logger (LOG_ERR, "read_info ROUTES `%s,%s,%s': invalid route", - dest, net, gate); - goto next; - } - - /* See if we can create a route */ - route = xzalloc (sizeof (*route)); - if (inet_aton (dest, &route->destination) == 0) { - logger (LOG_ERR, "read_info ROUTES `%s': not a valid destination address", - dest); - free (route); - goto next; - } - if (inet_aton (dest, &route->netmask) == 0) { - logger (LOG_ERR, "read_info ROUTES `%s': not a valid netmask address", - net); - free (route); - goto next; - } - if (inet_aton (dest, &route->gateway) == 0) { - logger (LOG_ERR, "read_info ROUTES `%s': not a valid gateway address", - gate); - free (route); - goto next; - } - - /* OK, now add our route */ - if (! dhcp->routes) { - dhcp->routes = xmalloc (sizeof (*dhcp->routes)); - STAILQ_INIT (dhcp->routes); - } - STAILQ_INSERT_TAIL (dhcp->routes, route, entries); - } - } else if (strcmp (var, "GATEWAYS") == 0) { - p = value; - while ((value = strsep (&p, " "))) { - route_t *route = xzalloc (sizeof (*route)); - if (parse_address (&route->gateway, value, "GATEWAYS")) { - if (! dhcp->routes) { - dhcp->routes = xmalloc (sizeof (*dhcp->routes)); - STAILQ_INIT (dhcp->routes); - } - STAILQ_INSERT_TAIL (dhcp->routes, route, entries); - } else - free (route); - } - } else if (strcmp (var, "HOSTNAME") == 0) - dhcp->hostname = xstrdup (value); - else if (strcmp (var, "DNSDOMAIN") == 0) - dhcp->dnsdomain = xstrdup (value); - else if (strcmp (var, "DNSSEARCH") == 0) - dhcp->dnssearch = xstrdup (value); - else if (strcmp (var, "DNSSERVERS") == 0) - dhcp->dnsservers = parse_addresses (value, "DNSSERVERS"); - else if (strcmp (var, "NTPSERVERS") == 0) - dhcp->ntpservers = parse_addresses (value, "NTPSERVERS"); - else if (strcmp (var, "NISDOMAIN") == 0) - dhcp->nisdomain = xstrdup (value); - else if (strcmp (var, "NISSERVERS") == 0) - dhcp->nisservers = parse_addresses (value, "NISSERVERS"); - else if (strcmp (var, "ROOTPATH") == 0) - dhcp->rootpath = xstrdup (value); - else if (strcmp (var, "DHCPSID") == 0) - parse_address (&dhcp->serveraddress, value, "DHCPSID"); - else if (strcmp (var, "DHCPSNAME") == 0) - strlcpy (dhcp->servername, value, sizeof (dhcp->servername)); - else if (strcmp (var, "LEASEDFROM") == 0) - parse_uint (&dhcp->leasedfrom, value, "LEASEDFROM"); - else if (strcmp (var, "LEASETIME") == 0) - parse_uint (&dhcp->leasetime, value, "LEASETIME"); - else if (strcmp (var, "RENEWALTIME") == 0) - parse_uint (&dhcp->renewaltime, value, "RENEWALTIME"); - else if (strcmp (var, "REBINDTIME") == 0) - parse_uint (&dhcp->rebindtime, value, "REBINDTIME"); - -next: - free (line); - } - - fclose (fp); - return (true); -} - -#endif - diff --git a/customdhcpcd/src/info.h b/customdhcpcd/src/info.h deleted file mode 100644 index 22966db..0000000 --- a/customdhcpcd/src/info.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef INFO_H -#define INFO_H - -#include "dhcpcd.h" -#include "interface.h" -#include "dhcp.h" - -#ifdef ENABLE_INFO -bool write_info (const interface_t *iface, const dhcp_t *dhcp, - const options_t *options, bool overwrite); - -bool read_info (const interface_t *iface, dhcp_t *dhcp); -#endif - -#endif diff --git a/customdhcpcd/src/interface.c b/customdhcpcd/src/interface.c deleted file mode 100644 index d2ff8d6..0000000 --- a/customdhcpcd/src/interface.c +++ /dev/null @@ -1,1060 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -#include - -/* Netlink suff */ -#ifdef __linux__ -#include /* Needed for 2.4 kernels */ -#include -#include -#include -#include -#else -#include -#include -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "common.h" -#include "dhcp.h" -#include "interface.h" -#include "logger.h" - -void free_address (struct address_head *addresses) -{ - address_t *p; - address_t *n; - - if (! addresses) - return; - - p = STAILQ_FIRST (addresses); - while (p) { - n = STAILQ_NEXT (p, entries); - free (p); - p = n; - } - free (addresses); -} - -void free_route (struct route_head *routes) -{ - route_t *p; - route_t *n; - - if (! routes) - return; - - p = STAILQ_FIRST (routes); - while (p) { - n = STAILQ_NEXT (p, entries); - free (p); - p = n; - } - free (routes); -} - -int inet_ntocidr (struct in_addr address) -{ - int cidr = 0; - uint32_t mask = htonl (address.s_addr); - - while (mask) { - cidr++; - mask <<= 1; - } - - return (cidr); -} - -int inet_cidrtoaddr (int cidr, struct in_addr *addr) { - int ocets; - - if (cidr < 0 || cidr > 32) { - errno = EINVAL; - return (-1); - } - ocets = (cidr + 7) / 8; - - memset (addr, 0, sizeof (*addr)); - if (ocets > 0) { - memset (&addr->s_addr, 255, (size_t) ocets - 1); - memset ((unsigned char *) &addr->s_addr + (ocets - 1), - (256 - (1 << (32 - cidr) % 8)), 1); - } - - return (0); -} - -uint32_t get_netmask (uint32_t addr) -{ - uint32_t dst; - - if (addr == 0) - return (0); - - dst = htonl (addr); - if (IN_CLASSA (dst)) - return (ntohl (IN_CLASSA_NET)); - if (IN_CLASSB (dst)) - return (ntohl (IN_CLASSB_NET)); - if (IN_CLASSC (dst)) - return (ntohl (IN_CLASSC_NET)); - - return (0); -} - -char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen) -{ - static char buffer[(HWADDR_LEN * 3) + 1]; - char *p = buffer; - size_t i; - - for (i = 0; i < hwlen && i < HWADDR_LEN; i++) { - if (i > 0) - *p ++= ':'; - p += snprintf (p, 3, "%.2x", hwaddr[i]); - } - - *p ++= '\0'; - - return (buffer); -} - -size_t hwaddr_aton (unsigned char *buffer, const char *addr) -{ - char c[3]; - const char *p = addr; - unsigned char *bp = buffer; - size_t len = 0; - - c[2] = '\0'; - while (*p) { - c[0] = *p++; - c[1] = *p++; - /* Ensure that next data is EOL or a seperator with data */ - if (! (*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) { - errno = EINVAL; - return (0); - } - /* Ensure that digits are hex */ - if (isxdigit ((int) c[0]) == 0 || isxdigit ((int) c[1]) == 0) { - errno = EINVAL; - return (0); - } - p++; - if (bp) - *bp++ = (unsigned char) strtol (c, NULL, 16); - else - len++; - } - - if (bp) - return (bp - buffer); - return (len); -} - -static int _do_interface (const char *ifname, - _unused unsigned char *hwaddr, _unused size_t *hwlen, - struct in_addr *addr, - bool flush, bool get) -{ - int s; - struct ifconf ifc; - int retval = 0; - int len = 10 * sizeof (struct ifreq); - int lastlen = 0; - char *p; - - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - /* Not all implementations return the needed buffer size for - * SIOGIFCONF so we loop like so for all until it works */ - memset (&ifc, 0, sizeof (ifc)); - for (;;) { - ifc.ifc_len = len; - ifc.ifc_buf = xmalloc ((size_t) len); - if (ioctl (s, SIOCGIFCONF, &ifc) == -1) { - if (errno != EINVAL || lastlen != 0) { - logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", - strerror (errno)); - close (s); - free (ifc.ifc_buf); - return -1; - } - } else { - if (ifc.ifc_len == lastlen) - break; - lastlen = ifc.ifc_len; - } - - free (ifc.ifc_buf); - ifc.ifc_buf = NULL; - len *= 2; - } - - for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) { - union { - char *buffer; - struct ifreq *ifr; - } ifreqs; - struct sockaddr_in address; - struct ifreq *ifr; - - /* Cast the ifc buffer to an ifreq cleanly */ - ifreqs.buffer = p; - ifr = ifreqs.ifr; - -#ifdef __linux__ - p += sizeof (*ifr); -#else - p += offsetof (struct ifreq, ifr_ifru) + ifr->ifr_addr.sa_len; -#endif - - if (strcmp (ifname, ifr->ifr_name) != 0) - continue; - -#ifdef AF_LINK - if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) { - struct sockaddr_dl sdl; - - memcpy (&sdl, &ifr->ifr_addr, sizeof (sdl)); - *hwlen = sdl.sdl_alen; - memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen, - (size_t) sdl.sdl_alen); - retval = 1; - break; - } -#endif - - if (ifr->ifr_addr.sa_family == AF_INET) { - memcpy (&address, &ifr->ifr_addr, sizeof (address)); - if (flush) { - struct sockaddr_in netmask; - - if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) { - logger (LOG_ERR, - "ioctl SIOCGIFNETMASK: %s", - strerror (errno)); - continue; - } - memcpy (&netmask, &ifr->ifr_addr, - sizeof (netmask)); - - if (del_address (ifname, - address.sin_addr, - netmask.sin_addr) == -1) - retval = -1; - } else if (get) { - addr->s_addr = address.sin_addr.s_addr; - retval = 1; - break; - } else if (address.sin_addr.s_addr == addr->s_addr) { - retval = 1; - break; - } - } - - } - - close (s); - free (ifc.ifc_buf); - return retval; -} - -interface_t *read_interface (const char *ifname, _unused int metric) -{ - int s; - struct ifreq ifr; - interface_t *iface = NULL; - unsigned char *hwaddr = NULL; - size_t hwlen = 0; - sa_family_t family = 0; - unsigned short mtu; -#ifdef __linux__ - char *p; -#endif - - if (! ifname) - return NULL; - - memset (&ifr, 0, sizeof (ifr)); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return NULL; - } - -#ifdef __linux__ - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); - goto exit; - } - - switch (ifr.ifr_hwaddr.sa_family) { - case ARPHRD_ETHER: - case ARPHRD_IEEE802: - hwlen = ETHER_ADDR_LEN; - break; - case ARPHRD_IEEE1394: - hwlen = EUI64_ADDR_LEN; - case ARPHRD_INFINIBAND: - hwlen = INFINIBAND_ADDR_LEN; - break; - default: - logger (LOG_ERR, - "interface is not Ethernet, FireWire, " \ - "InfiniBand or Token Ring"); - goto exit; - } - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); - family = ifr.ifr_hwaddr.sa_family; -#else - ifr.ifr_metric = metric; - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); - goto exit; - } - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) { - logger (LOG_ERR, "could not find interface %s", ifname); - goto exit; - } - - family = ARPHRD_ETHER; -#endif - - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCGIFMTU, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); - goto exit; - } - - if (ifr.ifr_mtu < MTU_MIN) { - logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", - ifr.ifr_mtu, MTU_MIN); - ifr.ifr_mtu = MTU_MIN; - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCSIFMTU, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", - strerror (errno)); - goto exit; - } - } - mtu = ifr.ifr_mtu; - - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); -#ifdef __linux__ - /* We can only bring the real interface up */ - if ((p = strchr (ifr.ifr_name, ':'))) - *p = '\0'; -#endif - if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); - goto exit; - } - - if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) { - ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - if (ioctl (s, SIOCSIFFLAGS, &ifr) != 0) { - logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", - strerror (errno)); - goto exit; - } - } - - iface = xzalloc (sizeof (*iface)); - strlcpy (iface->name, ifname, IF_NAMESIZE); -#ifdef ENABLE_INFO - snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); -#endif - memcpy (&iface->hwaddr, hwaddr, hwlen); - iface->hwlen = hwlen; - - iface->family = family; - iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)); - iface->mtu = iface->previous_mtu = mtu; - - logger (LOG_INFO, "hardware address = %s", - hwaddr_ntoa (iface->hwaddr, iface->hwlen)); - - /* 0 is a valid fd, so init to -1 */ - iface->fd = -1; -#ifdef __linux__ - iface->listen_fd = -1; -#endif - -exit: - close (s); - free (hwaddr); - return iface; -} - -int get_mtu (const char *ifname) -{ - struct ifreq ifr; - int r; - int s; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - - memset (&ifr, 0, sizeof (ifr)); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - r = ioctl (s, SIOCGIFMTU, &ifr); - close (s); - - if (r == -1) { - logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); - return (-1); - } - - return (ifr.ifr_mtu); -} - -int set_mtu (const char *ifname, short int mtu) -{ - struct ifreq ifr; - int r; - int s; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - - memset (&ifr, 0, sizeof (ifr)); - logger (LOG_DEBUG, "setting MTU to %d", mtu); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - ifr.ifr_mtu = mtu; - r = ioctl (s, SIOCSIFMTU, &ifr); - close (s); - - if (r == -1) - logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno)); - - return (r == 0 ? 0 : -1); -} - -static void log_route (struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - _unused int metric, - int change, int del) -{ - char *dstd = xstrdup (inet_ntoa (destination)); - -#ifdef __linux__ -#define METRIC " metric %d" -#else -#define METRIC "" -#endif - - if (gateway.s_addr == destination.s_addr || - gateway.s_addr == INADDR_ANY) - logger (LOG_INFO, "%s route to %s/%d" METRIC, - change ? "changing" : del ? "removing" : "adding", - dstd, inet_ntocidr (netmask) -#ifdef __linux__ - , metric -#endif - ); - else if (destination.s_addr == INADDR_ANY) - logger (LOG_INFO, "%s default route via %s" METRIC, - change ? "changing" : del ? "removing" : "adding", - inet_ntoa (gateway) - -#ifdef __linux__ - , metric -#endif - ); - else - logger (LOG_INFO, "%s route to %s/%d via %s" METRIC, - change ? "changing" : del ? "removing" : "adding", - dstd, inet_ntocidr (netmask), inet_ntoa (gateway) -#ifdef __linux__ - , metric -#endif - ); - - free (dstd); -} - -#if defined(BSD) || defined(__FreeBSD_kernel__) - -/* Darwin doesn't define this for some very odd reason */ -#ifndef SA_SIZE -# define SA_SIZE(sa) \ - ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ - sizeof(long) : \ - 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) -#endif - -static int do_address (const char *ifname, struct in_addr address, - struct in_addr netmask, struct in_addr broadcast, - int del) -{ - int s; - struct ifaliasreq ifa; - - if (! ifname) - return -1; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&ifa, 0, sizeof (ifa)); - strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name)); - -#define ADDADDR(_var, _addr) { \ - union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \ - _s.sa = &_var; \ - _s.sin->sin_family = AF_INET; \ - _s.sin->sin_len = sizeof (*_s.sin); \ - memcpy (&_s.sin->sin_addr, &_addr, sizeof (_s.sin->sin_addr)); \ -} - - ADDADDR (ifa.ifra_addr, address); - ADDADDR (ifa.ifra_mask, netmask); -if (! del) - ADDADDR (ifa.ifra_broadaddr, broadcast); - -#undef ADDADDR - - if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) { - logger (LOG_ERR, "ioctl %s: %s", - del ? "SIOCDIFADDR" : "SIOCAIFADDR", - strerror (errno)); - close (s); - return -1; - } - -close (s); -return 0; -} - -static int do_route (const char *ifname, - struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - int metric, - int change, int del) -{ - int s; - static int seq; - union sockunion { - struct sockaddr sa; - struct sockaddr_in sin; -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif - struct sockaddr_dl sdl; - struct sockaddr_storage ss; - } su; - struct rtm - { - struct rt_msghdr hdr; - char buffer[sizeof (su) * 3]; - } rtm; - char *bp = rtm.buffer; - size_t l; - - if (! ifname) - return -1; - - log_route (destination, netmask, gateway, metric, change, del); - - if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&rtm, 0, sizeof (rtm)); - - rtm.hdr.rtm_version = RTM_VERSION; - rtm.hdr.rtm_seq = ++seq; - rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD; - rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC; - - /* This order is important */ - rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; - -#define ADDADDR(_addr) \ - memset (&su, 0, sizeof (su)); \ - su.sin.sin_family = AF_INET; \ - su.sin.sin_len = sizeof (su.sin); \ - memcpy (&su.sin.sin_addr, &_addr, sizeof (su.sin.sin_addr)); \ - l = SA_SIZE (&(su.sa)); \ - memcpy (bp, &(su), l); \ - bp += l; - - ADDADDR (destination); - - if (netmask.s_addr == INADDR_BROADCAST || - gateway.s_addr == INADDR_ANY) - { - /* Make us a link layer socket */ - unsigned char *hwaddr; - size_t hwlen = 0; - - if (netmask.s_addr == INADDR_BROADCAST) - rtm.hdr.rtm_flags |= RTF_HOST; - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); - memset (&su, 0, sizeof (su)); - su.sdl.sdl_len = sizeof (su.sdl); - su.sdl.sdl_family = AF_LINK; - su.sdl.sdl_nlen = strlen (ifname); - memcpy (&su.sdl.sdl_data, ifname, (size_t) su.sdl.sdl_nlen); - su.sdl.sdl_alen = hwlen; - memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, - hwaddr, (size_t) su.sdl.sdl_alen); - - l = SA_SIZE (&(su.sa)); - memcpy (bp, &su, l); - bp += l; - free (hwaddr); - } else { - rtm.hdr.rtm_flags |= RTF_GATEWAY; - ADDADDR (gateway); - } - - ADDADDR (netmask); -#undef ADDADDR - - rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; - if (write (s, &rtm, l) == -1) { - /* Don't report error about routes already existing */ - if (errno != EEXIST) - logger (LOG_ERR, "write: %s", strerror (errno)); - close (s); - return -1; - } - - close (s); - return 0; -} - -#elif __linux__ -/* This netlink stuff is overly compex IMO. - * The BSD implementation is much cleaner and a lot less code. - * send_netlink handles the actual transmission so we can work out - * if there was an error or not. */ -#define BUFFERLEN 256 -int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg) -{ - int s; - pid_t mypid = getpid (); - struct sockaddr_nl nl; - struct iovec iov; - struct msghdr msg; - static unsigned int seq; - char *buffer; - ssize_t bytes; - union - { - char *buffer; - struct nlmsghdr *nlm; - } h; - - if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&nl, 0, sizeof (nl)); - nl.nl_family = AF_NETLINK; - if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) { - logger (LOG_ERR, "bind: %s", strerror (errno)); - close (s); - return -1; - } - - memset (&iov, 0, sizeof (iov)); - iov.iov_base = hdr; - iov.iov_len = hdr->nlmsg_len; - - memset (&msg, 0, sizeof (msg)); - msg.msg_name = &nl; - msg.msg_namelen = sizeof (nl); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - /* Request a reply */ - hdr->nlmsg_flags |= NLM_F_ACK; - hdr->nlmsg_seq = ++seq; - - if (sendmsg (s, &msg, 0) == -1) { - logger (LOG_ERR, "write: %s", strerror (errno)); - close (s); - return -1; - } - - buffer = xzalloc (sizeof (char) * BUFFERLEN); - iov.iov_base = buffer; - - for (;;) { - iov.iov_len = BUFFERLEN; - bytes = recvmsg (s, &msg, 0); - - if (bytes == -1) { - if (errno != EINTR) - logger (LOG_ERR, "recvmsg: %s", - strerror (errno)); - continue; - } - - if (bytes == 0) { - logger (LOG_ERR, "netlink: EOF"); - goto eexit; - } - - if (msg.msg_namelen != sizeof (nl)) { - logger (LOG_ERR, - "netlink: sender address length mismatch"); - goto eexit; - } - - for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) { - int len = h.nlm->nlmsg_len; - int l = len - sizeof (*h.nlm); - struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); - - if (l < 0 || len > bytes) { - if (msg.msg_flags & MSG_TRUNC) - logger (LOG_ERR, "netlink: truncated message"); - else - logger (LOG_ERR, "netlink: malformed message"); - goto eexit; - } - - /* Ensure it's our message */ - if (nl.nl_pid != 0 || - (pid_t) h.nlm->nlmsg_pid != mypid || - h.nlm->nlmsg_seq != seq) - { - /* Next Message */ - bytes -= NLMSG_ALIGN (len); - h.buffer += NLMSG_ALIGN (len); - continue; - } - - /* We get an NLMSG_ERROR back with a code of zero for success */ - if (h.nlm->nlmsg_type != NLMSG_ERROR) { - logger (LOG_ERR, "netlink: unexpected reply %d", - h.nlm->nlmsg_type); - goto eexit; - } - - if ((unsigned) l < sizeof (*err)) { - logger (LOG_ERR, "netlink: error truncated"); - goto eexit; - } - - if (err->error == 0) { - int retval = 0; - - close (s); - if (callback) { - if ((retval = callback (hdr, arg)) == -1) - logger (LOG_ERR, "netlink: callback failed"); - } - free (buffer); - return (retval); - } - - errno = -err->error; - /* Don't report on something already existing */ - if (errno != EEXIST) - logger (LOG_ERR, "netlink: %s", - strerror (errno)); - goto eexit; - } - } - -eexit: - close (s); - free (buffer); - return -1; -} - -#define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) - -static int add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type, - const void *data, int alen) -{ - int len = RTA_LENGTH(alen); - struct rtattr *rta; - - if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) { - logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n", - maxlen); - return -1; - } - - rta = NLMSG_TAIL (n); - rta->rta_type = type; - rta->rta_len = len; - memcpy (RTA_DATA (rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len); - - return 0; -} - -static int add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, - uint32_t data) -{ - int len = RTA_LENGTH (sizeof (data)); - struct rtattr *rta; - - if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) { - logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", - maxlen); - return -1; - } - - rta = NLMSG_TAIL (n); - rta->rta_type = type; - rta->rta_len = len; - memcpy (RTA_DATA (rta), &data, sizeof (data)); - n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; - - return 0; -} - -struct nlma -{ - struct nlmsghdr hdr; - struct ifaddrmsg ifa; - char buffer[64]; -}; - -struct nlmr -{ - struct nlmsghdr hdr; - struct rtmsg rt; - char buffer[256]; -}; - -static int do_address(const char *ifname, - struct in_addr address, struct in_addr netmask, - struct in_addr broadcast, int del) -{ - struct nlma *nlm; - int retval; - - if (!ifname) - return -1; - - nlm = xzalloc (sizeof (*nlm)); - nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); - nlm->hdr.nlmsg_flags = NLM_F_REQUEST; - if (! del) - nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; - if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) { - logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", - ifname); - free (nlm); - return -1; - } - nlm->ifa.ifa_family = AF_INET; - - nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask); - - /* This creates the aliased interface */ - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LABEL, - ifname, strlen (ifname) + 1); - - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LOCAL, - &address.s_addr, sizeof (address.s_addr)); - if (! del) - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST, - &broadcast.s_addr, sizeof (broadcast.s_addr)); - - retval = send_netlink (&nlm->hdr, NULL, NULL); - free (nlm); - return retval; -} - -static int do_route (const char *ifname, - struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - int metric, int change, int del) -{ - struct nlmr *nlm; - unsigned int ifindex; - int retval; - - if (! ifname) - return -1; - - log_route (destination, netmask, gateway, metric, change, del); - - if (! (ifindex = if_nametoindex (ifname))) { - logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", - ifname); - return -1; - } - - nlm = xzalloc (sizeof (*nlm)); - nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); - if (change) - nlm->hdr.nlmsg_flags = NLM_F_REPLACE; - else if (! del) - nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; - nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; - nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; - nlm->rt.rtm_family = AF_INET; - nlm->rt.rtm_table = RT_TABLE_MAIN; - - if (del) - nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; - else { - nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; - nlm->rt.rtm_protocol = RTPROT_BOOT; - if (netmask.s_addr == INADDR_BROADCAST || - gateway.s_addr == INADDR_ANY) - nlm->rt.rtm_scope = RT_SCOPE_LINK; - else - nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; - nlm->rt.rtm_type = RTN_UNICAST; - } - - nlm->rt.rtm_dst_len = inet_ntocidr (netmask); - add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_DST, - &destination.s_addr, sizeof (destination.s_addr)); - if (netmask.s_addr != INADDR_BROADCAST && - destination.s_addr != gateway.s_addr) - add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_GATEWAY, - &gateway.s_addr, sizeof (gateway.s_addr)); - - add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex); - add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric); - - retval = send_netlink (&nlm->hdr, NULL, NULL); - free (nlm); - return retval; -} - -#else - #error "Platform not supported!" - #error "We currently support BPF and Linux sockets." - #error "Other platforms may work using BPF. If yours does, please let me know" - #error "so I can add it to our list." -#endif - -int add_address (const char *ifname, struct in_addr address, - struct in_addr netmask, struct in_addr broadcast) -{ - logger (LOG_INFO, "adding IP address %s/%d", - inet_ntoa (address), inet_ntocidr (netmask)); - - return (do_address (ifname, address, netmask, broadcast, 0)); -} - -int del_address (const char *ifname, - struct in_addr address, struct in_addr netmask) -{ - struct in_addr t; - - logger (LOG_INFO, "removing IP address %s/%d", - inet_ntoa (address), inet_ntocidr (netmask)); - - memset (&t, 0, sizeof (t)); - return (do_address (ifname, address, netmask, t, 1)); -} - -int add_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) -{ - return (do_route (ifname, destination, netmask, gateway, metric, 0, 0)); -} - -int change_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) -{ - return (do_route (ifname, destination, netmask, gateway, metric, 1, 0)); -} - -int del_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) -{ - return (do_route (ifname, destination, netmask, gateway, metric, 0, 1)); -} - - -int flush_addresses (const char *ifname) -{ - return (_do_interface (ifname, NULL, NULL, NULL, true, false)); -} - -in_addr_t get_address (const char *ifname) -{ - struct in_addr address; - if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0) - return (address.s_addr); - return (0); -} - -int has_address (const char *ifname, struct in_addr address) -{ - return (_do_interface (ifname, NULL, NULL, &address, false, false)); -} diff --git a/customdhcpcd/src/interface.h b/customdhcpcd/src/interface.h deleted file mode 100644 index 8215d48..0000000 --- a/customdhcpcd/src/interface.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef INTERFACE_H -#define INTERFACE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#ifdef __linux__ -# include -#endif - -#ifdef ENABLE_DUID -#ifndef DUID_LEN -# define DUID_LEN 128 + 2 -#endif -#endif - -#define EUI64_ADDR_LEN 8 -#define INFINIBAND_ADDR_LEN 20 - -/* Linux 2.4 doesn't define this */ -#ifndef ARPHRD_IEEE1394 -# define ARPHRD_IEEE1394 24 -#endif - -/* The BSD's don't define this yet */ -#ifndef ARPHRD_INFINIBAND -# define ARPHRD_INFINIBAND 32 -#endif - -#define HWADDR_LEN 20 - -/* Work out if we have a private address or not - * 10/8 - * 172.16/12 - * 192.168/16 - */ -#ifndef IN_PRIVATE -# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \ - ((addr & 0xfff00000) == 0xac100000) || \ - ((addr & IN_CLASSB_NET) == 0xc0a80000)) -#endif - -#define LINKLOCAL_ADDR 0xa9fe0000 -#define LINKLOCAL_MASK 0xffff0000 -#define LINKLOCAL_BRDC 0xa9feffff - -#ifndef IN_LINKLOCAL -# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR) -#endif - -#ifndef STAILQ_ENTRY -# error "your sys/queue.h is too old and lacks STAILQ" -#endif - -#define NSTAILQ_FOREACH(var, head, field) \ - if (head) STAILQ_FOREACH (var, head, field) - -typedef struct route_t -{ - struct in_addr destination; - struct in_addr netmask; - struct in_addr gateway; - STAILQ_ENTRY (route_t) entries; -} route_t; -STAILQ_HEAD (route_head, route_t); - -typedef struct address_t -{ - struct in_addr address; - STAILQ_ENTRY (address_t) entries; -} address_t; -STAILQ_HEAD (address_head, address_t); - -typedef struct interface_t -{ - char name[IF_NAMESIZE]; - sa_family_t family; - unsigned char hwaddr[HWADDR_LEN]; - size_t hwlen; - bool arpable; - unsigned short mtu; - - int fd; - size_t buffer_length; - -#ifdef __linux__ - int listen_fd; - int socket_protocol; -#endif - - char infofile[PATH_MAX]; - - unsigned short previous_mtu; - struct in_addr previous_address; - struct in_addr previous_netmask; - struct route_head *previous_routes; - - time_t start_uptime; - - unsigned char *clientid; - size_t clientid_len; -} interface_t; - -void free_address (struct address_head *addresses); -void free_route (struct route_head *routes); -uint32_t get_netmask (uint32_t addr); -char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen); -size_t hwaddr_aton (unsigned char *hwaddr, const char *addr); - -interface_t *read_interface (const char *ifname, int metric); -int get_mtu (const char *ifname); -int set_mtu (const char *ifname, short int mtu); - -int add_address (const char *ifname, struct in_addr address, - struct in_addr netmask, struct in_addr broadcast); -int del_address (const char *ifname, struct in_addr address, - struct in_addr netmask); - -int flush_addresses (const char *ifname); -in_addr_t get_address (const char *ifname); -int has_address (const char *ifname, struct in_addr address); - -int add_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric); -int change_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric); -int del_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric); - -int inet_ntocidr (struct in_addr address); -int inet_cidrtoaddr (int cidr, struct in_addr *addr); - -#ifdef __linux__ -typedef int (*netlink_callback) (struct nlmsghdr *hdr, void *arg); -int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg); -#endif -#endif diff --git a/customdhcpcd/src/ipv4ll.c b/customdhcpcd/src/ipv4ll.c deleted file mode 100644 index 9742b9a..0000000 --- a/customdhcpcd/src/ipv4ll.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include - -#include "config.h" -#include "arp.h" -#include "ipv4ll.h" - -#ifdef ENABLE_IPV4LL - -#ifndef ENABLE_ARP - # error IPV4LL requires ARP -#endif - -#define IPV4LL_LEASETIME 20 - -int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp) { - struct in_addr addr; - - for (;;) { - addr.s_addr = htonl (LINKLOCAL_ADDR | - (((uint32_t) abs ((int) random ()) - % 0xFD00) + 0x0100)); - errno = 0; - if (! arp_claim (iface, addr)) - break; - /* Our ARP may have been interrupted */ - if (errno) - return (-1); - } - - dhcp->address.s_addr = addr.s_addr; - dhcp->netmask.s_addr = htonl (LINKLOCAL_MASK); - dhcp->broadcast.s_addr = htonl (LINKLOCAL_BRDC); - - /* Finally configure some DHCP like lease times */ - dhcp->leasetime = IPV4LL_LEASETIME; - dhcp->renewaltime = (dhcp->leasetime * 0.5); - dhcp->rebindtime = (dhcp->leasetime * 0.875); - - return (0); -} - -#endif diff --git a/customdhcpcd/src/ipv4ll.h b/customdhcpcd/src/ipv4ll.h deleted file mode 100644 index 4fa8943..0000000 --- a/customdhcpcd/src/ipv4ll.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef IPV4LL_H -#define IPV4LL_H - -#ifdef ENABLE_IPV4LL - -#include "dhcp.h" -#include "interface.h" - -int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp); - -#endif -#endif diff --git a/customdhcpcd/src/logger.c b/customdhcpcd/src/logger.c deleted file mode 100644 index 2c8431d..0000000 --- a/customdhcpcd/src/logger.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define SYSLOG_NAMES - -#define COM_CH "/var/tmp/com.socket" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "logger.h" -#include "logwriter.h" - -static int loglevel = LOG_WARNING; -static char logprefix[12] = { 0 }; - -int logtolevel(const char *priority) { - CODE *c; - - if (isdigit ((int) *priority)) - return (atoi(priority)); - - for (c = prioritynames; c->c_name; c++) - if (!strcasecmp(priority, c->c_name)) - return (c->c_val); - - return (-1); -} - -static const char *leveltolog(int level) { - CODE *c; - - for (c = prioritynames; c->c_name; c++) - if (c->c_val == level) - return (c->c_name); - - return (NULL); -} - -void setloglevel(int level) { - loglevel = level; -} - -void setlogprefix(const char *prefix) { - snprintf(logprefix, sizeof(logprefix), "%s", prefix); -} - -void logger(int level, const char *fmt, ...) { - va_list p; - //va_list p2; -// FILE *f = stderr; - FILE *f; - FILE *f2; - char* path = "/tmp/cdhcpcd.log"; - char* msgpath = "/tmp/cdhcpcd-msg.log"; - int size = 512; - char *msg = (char *) malloc (size); - - - f = fopen(path,"a"); - f2 = fopen(msgpath,"a"); - va_start (p, fmt); - //va_copy (p2, p); - - - vsnprintf (msg, size, fmt, p); - strcat(msg,"\n"); - logToQt(level, DHCPCD_LOG, msg); - - fprintf(f2, "%s, %s", leveltolog(level), logprefix); - fprintf(f2, "%s", msg); - fputc('\n', f2); - - fprintf(f, "%s, %s", leveltolog(level), logprefix); - vfprintf(f, fmt, p); - fputc('\n', f); - - /* stdout, stderr may be re-directed to some kind of buffer. - * So we always flush to ensure it's written. */ - fflush(f); - -// //logLoggerToQt(level, fmt, p); -// if (level <= LOG_ERR || level <= loglevel) { -// -// /* new function by Niklas Goby -// * send the log message also to our Qt programm. -// * implemented in logwriter.c -// * */ -// //logLoggerToQt(level, fmt, p); -// -// if (level == LOG_DEBUG || level == LOG_INFO) -// f = stdout; -// fprintf(f, "%s, %s", leveltolog(level), logprefix); -// vfprintf(f, fmt, p); -// fputc('\n', f); -// -// /* stdout, stderr may be re-directed to some kind of buffer. -// * So we always flush to ensure it's written. */ -// fflush(f); -// } -// if (level < LOG_DEBUG || level <= loglevel) { -// size_t len = strlen(logprefix); -// size_t fmt2len = strlen(fmt) + len + 1; -// char *fmt2 = malloc(sizeof(char) * fmt2len); -// char *pf = fmt2; -// if (fmt2) { -// memcpy(pf, logprefix, len); -// pf += len; -// strlcpy(pf, fmt, fmt2len - len); -// vsyslog(level, fmt2, p2); -// free(fmt2); -// } else { -// vsyslog(level, fmt, p2); -// syslog(LOG_ERR, "logger: memory exhausted"); -// exit(EXIT_FAILURE); -// } -// } - - //va_end (p2); - va_end (p); -} - diff --git a/customdhcpcd/src/logger.h b/customdhcpcd/src/logger.h deleted file mode 100644 index 70e2ed5..0000000 --- a/customdhcpcd/src/logger.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef LOGGER_H -#define LOGGER_H - -#if defined(__GNUC__) -# define _PRINTF_LIKE(_one, _two) __attribute__ ((__format__ (__printf__, _one, _two))) -#else -# define _PRINTF_LIKE(_one, _two) -#endif - -#include - - - -int logtolevel (const char *priority); -void setloglevel (int level); -void setlogprefix (const char *prefix); -void logger (int level, const char *fmt, ...) _PRINTF_LIKE (2, 3); - - - -#endif diff --git a/customdhcpcd/src/logwriter.c b/customdhcpcd/src/logwriter.c deleted file mode 100644 index 6230d4c..0000000 --- a/customdhcpcd/src/logwriter.c +++ /dev/null @@ -1,260 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "dhcp.h" -#include "dhcpcd.h" -#include "errno.h" -#include "info.h" -#include "logger.h" -#include "logwriter.h" - -#include "../../common/fbgui.h" // for constants -/*sockets for the logger and the qt-reader */ -int sockfd, ns; -int retval = -1; -char socketName[QTSOCKETADDRESSLENGTH]; -char interfaceName[IF_NAMESIZE]; - -void setSocketName(const char * sn) { - snprintf(socketName, sizeof(socketName), "%s", sn); -} - -void setInterfaceName(const char * in) { - snprintf(interfaceName, sizeof(interfaceName), "%s", in); -} - -int initQtLoggerSocket() { - /** - * new code. seems to be right. - */ - - struct sockaddr_un serv_addr; - fprintf(stdout, "start init \n"); - sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - if (sockfd < 0) { - fprintf(stdout, "ERROR opening socket \n"); - retval = sockfd; - return sockfd; - } - serv_addr.sun_family = AF_UNIX; - strcpy(serv_addr.sun_path, socketName); - - retval = connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); - if (retval < 0) - fprintf(stdout, "ERROR connecting \n"); - fprintf(stdout, "init Qt Logger Socket done \n"); - return retval; -} - -void closeQtLoggerSocket() { - close(sockfd); -} - -void sendToQt(log_msg * msg) { - int n = -1; - int t; - int ret; - const char *tpl = "%s;%d;%d;%s\n"; - char outbuf[DHCP_MESSAGE_SIZE]; - char ack[ACK_SIZE]; - /* - size_t outbuf_size = sizeof(char) * 4 + // ";" *3 + newline - sizeof(int) * 2 + // status, substatus - sizeof(msg->device) + // devicename - sizeof(msg->msg); // msg - outbuf = malloc(outbuf_size); - memset(outbuf, 0, outbuf_size); - snprintf(outbuf, sizeof(char) * 3 + sizeof(int) * 2 + sizeof(msg->device) - + sizeof(msg->msg), tpl, msg->device, msg->status, msg->substatus, - msg->msg); - */ - memset(outbuf, '\0', DHCP_MESSAGE_SIZE); - ret = snprintf(outbuf, DHCP_MESSAGE_SIZE, tpl, msg->device, msg->status, - msg->substatus, msg->msg); - if (ret < 1) { - log ger(LOG_INFO, "[fbgui] ERROR filling message buffer"); - //syslog(LOG_INFO, "[fbgui] ERROR filling message buffer"); - return; - } - if (outbuf != NULL) { - n = send(sockfd, outbuf, DHCP_MESSAGE_SIZE, 0); - } - syslog(LOG_INFO, "[fbgui] INFO writing to socket: [%d:%d] %s (%s)", - msg->status, msg->substatus, msg->msg, msg->device); - - if (n <= 0) { - logger(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)", - msg->status, msg->substatus, msg->msg, msg->device); - //syslog(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)", - // msg->status, msg->substatus, msg->msg, msg->device); - } - /* - memset(ack, 0, ACK_SIZE); - if ((t = recv(sockfd, ack, ACK_SIZE, 0)) > 0) { - syslog(LOG_ERR, "[fbgui] recv ack echo> %s", ack); - printf("received: %s\n", ack); - } else { - if (t < 0) - syslog(LOG_ERR, "[fbgui] ERROR receiving from socket"); - else - syslog(LOG_ERR, "[fbgui] ERROR Server closed"); - } - */ -} - - - -void logToQt(int status, int substatus, const char * msg) { - if (retval >= 0) { - log_msg lm; - lm.status = status; - lm.substatus = substatus; - snprintf(lm.msg, sizeof(lm.msg), "%s", msg); - snprintf(lm.device, sizeof(lm.device), "%s", interfaceName); - sendToQt(&lm); - } -} - - - -void logSendToQt(int type) { - switch (type) { - case DHCP_DISCOVER: - logToQt(LOG_INFO, DHCP_DISCOVER, "send discover"); - break; - case DHCP_OFFER: - logToQt(LOG_INFO, DHCP_OFFER, "send offer"); - break; - case DHCP_REQUEST: - logToQt(LOG_INFO, DHCP_REQUEST, "send request"); - break; - case DHCP_DECLINE: - logToQt(LOG_INFO, DHCP_DECLINE, "send decline"); - break; - case DHCP_ACK: - logToQt(LOG_INFO, DHCP_ACK, "send ack"); - break; - case DHCP_NAK: - logToQt(LOG_INFO, DHCP_NAK, "send nak"); - break; - case DHCP_RELEASE: - logToQt(LOG_INFO, DHCP_RELEASE, "send release"); - break; - case DHCP_INFORM: - logToQt(LOG_INFO, DHCP_INFORM, "send inform"); - break; - default: - break; - } -} - - - -static void print_addresses (FILE *f, const struct address_head *addresses) -{ - const address_t *addr; - - STAILQ_FOREACH (addr, addresses, entries) { - fprintf (f, "%s", inet_ntoa (addr->address)); - if (STAILQ_NEXT (addr, entries)) - fprintf (f, " "); - } -} - - - -void logGatewayToFile(const interface_t *iface, const dhcp_t *dhcp) { - /*void logGatewayToFile(const interface_t iface, const dhcp_t *dhcp, - const options_t options)*/ - //char path[QTSOCKETADDRESSLENGTH]; - - /* - strcpy(path, DEFAULT_GATEWAY_INFO_LOCATION); - strcat(path, iface.name); - strcpy(iface.infofile, path); - options.test = false; - syslog(LOG_INFO, "[fbgui] try to open file: %s", iface.infofile); - write_info(&iface, dhcp, &options, true); - */ - FILE *f; - route_t *route; - char path[QTSOCKETADDRESSLENGTH]; - - strcpy(path, DEFAULT_INTERFACE_CONF_LOCATION); - strcat(path, iface->name); - - syslog(LOG_INFO, "[fbgui] try to open file: %s", path); - - logger(LOG_DEBUG, "writing %s", iface->infofile); - if ((f = fopen(path, "w")) == NULL) { - logger(LOG_ERR, "fopen `%s': %s", path, strerror(errno)); - //TODO: exit/return .. - return; - } - - if (dhcp->address.s_addr) { - struct in_addr n; - n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; - fprintf(f, "IPADDR='%s'\n", inet_ntoa(dhcp->address)); - fprintf(f, "NETMASK='%s'\n", inet_ntoa(dhcp->netmask)); - fprintf(f, "NETWORK='%s'\n", inet_ntoa(n)); - fprintf(f, "BROADCAST='%s'\n", inet_ntoa(dhcp->broadcast)); - } - - if (dhcp->routes) { - bool doneone = false; - fprintf(f, "ROUTES='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr != 0) { - if (doneone) - fprintf(f, " "); - fprintf(f, "%s", inet_ntoa(route->destination)); - fprintf(f, ",%s", inet_ntoa(route->netmask)); - fprintf(f, ",%s", inet_ntoa(route->gateway)); - doneone = true; - } - } - fprintf(f, "'\n"); - - doneone = false; - fprintf(f, "GATEWAYS='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr == 0) { - if (doneone) - fprintf(f, " "); - fprintf(f, "%s", inet_ntoa(route->gateway)); - doneone = true; - } - } - fprintf(f, "'\n"); - } - - fprintf(f, "HOSTNAME='%s", dhcp->hostname); - fprintf(f, "'\n"); - fprintf(f, "DNSSEARCH='%s", dhcp->dnssearch); - fprintf(f, "'\n"); - - if (dhcp->dnsservers) { - fprintf(f, "DNSSERVERS='"); - print_addresses(f, dhcp->dnsservers); - fprintf(f, "'\n"); - } - fprintf(f, "INTERFACE='%s", iface->name); - fprintf(f, "'\n"); - if (iface->clientid_len > 0) { - fprintf(f, "CLIENTID='%s'\n", hwaddr_ntoa(iface->clientid, - iface->clientid_len)); - } - fprintf(f, "DHCPCHADDR='%s'\n", hwaddr_ntoa(iface->hwaddr, iface->hwlen)); - fclose(f); -} diff --git a/customdhcpcd/src/logwriter.h b/customdhcpcd/src/logwriter.h deleted file mode 100644 index 43f35fa..0000000 --- a/customdhcpcd/src/logwriter.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * logwriter.h - * - * Created on: Jul 7, 2011 - * Author: niklas - */ - -#ifndef LOGWRITER_H_ -#define LOGWRITER_H_ - -#include -#include "dhcp.h" -#include "interface.h" -#include "dhcpcd.h" - -#define LOG_MSG_SIZE 1024 - -typedef struct _log_msg log_msg; -struct _log_msg { - int status; - int substatus; - char device[IF_NAMESIZE]; - char msg[LOG_MSG_SIZE]; -}; - -/** - * new functions for communicating with Qt - */ -void setSocketName(const char * sn); -void setInterfaceName(const char * in); -int initQtLoggerSocket (); -void closeQtLoggerSocket (); -void sendToQt (); -void logToQt(int status, int substatus, const char * msg); -void logSendToQt(int type); -void logLoggerToQt(int level, const char *fmt, ...); -//void logToQt(char * status, char * substatus, char * msg); -void logGatewayToFile(const interface_t *iface, const dhcp_t *dhcp); - -#endif /* LOGWRITER_H_ */ diff --git a/customdhcpcd/src/signal.c b/customdhcpcd/src/signal.c deleted file mode 100644 index 9055c9f..0000000 --- a/customdhcpcd/src/signal.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "logger.h" -#include "signal.h" - -static int signal_pipe[2]; -static int signals[5]; - -static const int handle_sigs[] = { - SIGHUP, - SIGALRM, - SIGTERM, - SIGINT -}; - -static void signal_handler (int sig) -{ - unsigned int i = 0; - int serrno = errno; - - /* Add a signal to our stack */ - while (signals[i]) - i++; - if (i > sizeof (signals) / sizeof (signals[0])) - logger (LOG_ERR, "signal buffer overrun"); - else - signals[i] = sig; - - if (write (signal_pipe[1], &sig, sizeof (sig)) == -1) - logger (LOG_ERR, "Could not send signal: %s", strerror (errno)); - - /* Restore errno */ - errno = serrno; -} - -int signal_fd (void) -{ - return (signal_pipe[0]); -} - -/* Check if we have a signal or not */ -int signal_exists (const struct pollfd *fd) -{ - if (signals[0] || (fd && fd->revents & POLLIN)) - return (0); - return (-1); -} - -/* Read a signal from the signal pipe. Returns 0 if there is - * no signal, -1 on error (and sets errno appropriately), and - * your signal on success */ -int signal_read (struct pollfd *fd) -{ - int sig = -1; - - /* Pop a signal off the our stack */ - if (signals[0]) { - unsigned int i = 0; - sig = signals[0]; - while (i < (sizeof (signals) / sizeof (signals[0])) - 1) { - signals[i] = signals[i + 1]; - if (! signals[++i]) - break; - } - } - - if (fd && fd->revents & POLLIN) { - char buf[16]; - size_t bytes; - - memset (buf, 0, sizeof (buf)); - bytes = read (signal_pipe[0], buf, sizeof (buf)); - - if (bytes >= sizeof (sig)) - memcpy (&sig, buf, sizeof (sig)); - - /* We need to clear us from rset if nothing left in the buffer - * in case we are called many times */ - if (bytes == sizeof (sig)) - fd->revents = 0; - } - - return (sig); -} - -/* Call this before doing anything else. Sets up the socket pair - * and installs the signal handler */ -int signal_init (void) -{ - struct sigaction sa; - - if (pipe (signal_pipe) == -1) { - logger (LOG_ERR, "pipe: %s", strerror (errno)); - return (-1); - } - - /* Stop any scripts from inheriting us */ - close_on_exec (signal_pipe[0]); - close_on_exec (signal_pipe[1]); - - /* Ignore child signals and don't make zombies. - * Because we do this, we don't need to be in signal_setup */ - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = SIG_DFL; - sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT; - if (sigaction (SIGCHLD, &sa, NULL) == -1) { - logger (LOG_ERR, "sigaction: %s", strerror (errno)); - return (-1); - } - - memset (signals, 0, sizeof (signals)); - return (0); -} - -int signal_setup (void) -{ - unsigned int i; - struct sigaction sa; - - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = signal_handler; - sigemptyset (&sa.sa_mask); - - for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) - if (sigaction (handle_sigs[i], &sa, NULL) == -1) { - logger (LOG_ERR, "sigaction: %s", strerror (errno)); - return (-1); - } - - return (0); -} - -int signal_reset (void) -{ - struct sigaction sa; - unsigned int i; - - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = SIG_DFL; - sigemptyset (&sa.sa_mask); - - for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) - if (sigaction (handle_sigs[i], &sa, NULL) == -1) { - logger (LOG_ERR, "sigaction: %s", strerror (errno)); - return (-1); - } - - return (0); -} diff --git a/customdhcpcd/src/signal.h b/customdhcpcd/src/signal.h deleted file mode 100644 index 63a5906..0000000 --- a/customdhcpcd/src/signal.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef SIGNAL_H -#define SIGNAL_H - -#include - -int signal_init (void); -int signal_setup (void); -int signal_reset (void); -int signal_fd (void); -int signal_exists (const struct pollfd *fd); -int signal_read (struct pollfd *fd); - -#endif diff --git a/customdhcpcd/src/socket.c b/customdhcpcd/src/socket.c deleted file mode 100644 index 58ad6c5..0000000 --- a/customdhcpcd/src/socket.c +++ /dev/null @@ -1,647 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#define __FAVOR_BSD /* Nasty hack so we can use BSD semantics for UDP */ -#include -#undef __FAVOR_BSD -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(BSD) || defined(__FreeBSD_kernel__) -# include -#elif __linux__ -# include -# include -# define bpf_insn sock_filter -#endif - -#include "config.h" -#include "dhcp.h" -#include "interface.h" -#include "logger.h" -#include "socket.h" - -/* A suitably large buffer for all transactions. - * BPF buffer size is set by the kernel, so no define. */ -#ifdef __linux__ -# define BUFFER_LENGTH 4096 -#endif - -/* Broadcast address for IPoIB */ -static const uint8_t ipv4_bcast_addr[] = { - 0x00, 0xff, 0xff, 0xff, - 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff -}; - -/* Credit where credit is due :) - * The below BPF filter is taken from ISC DHCP */ -static struct bpf_insn dhcp_bpf_filter [] = { - /* Make sure this is an IP packet... */ - BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), - - /* Make sure it's a UDP packet... */ - BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), - - /* Make sure this isn't a fragment... */ - BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), - BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), - - /* Get the IP header length... */ - BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), - - /* Make sure it's to the right port... */ - BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1), - - /* If we passed all the tests, ask for the whole packet. */ - BPF_STMT (BPF_RET + BPF_K, ~0U), - - /* Otherwise, drop it. */ - BPF_STMT (BPF_RET + BPF_K, 0), -}; - -static struct bpf_insn arp_bpf_filter [] = { - /* Make sure this is an ARP packet... */ - BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3), - - /* Make sure this is an ARP REPLY... */ - BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), - - /* If we passed all the tests, ask for the whole packet. */ - BPF_STMT (BPF_RET + BPF_K, ~0U), - - /* Otherwise, drop it. */ - BPF_STMT (BPF_RET + BPF_K, 0), -}; - -void setup_packet_filters (void) -{ -#ifdef __linux__ - /* We need to massage the filters for Linux cooked packets */ - dhcp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ - dhcp_bpf_filter[2].k -= ETH_HLEN; - dhcp_bpf_filter[4].k -= ETH_HLEN; - dhcp_bpf_filter[6].k -= ETH_HLEN; - dhcp_bpf_filter[7].k -= ETH_HLEN; - - arp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ - arp_bpf_filter[2].k -= ETH_HLEN; -#endif -} - -static uint16_t checksum (unsigned char *addr, uint16_t len) -{ - uint32_t sum = 0; - union - { - unsigned char *addr; - uint16_t *i; - } p; - uint16_t nleft = len; - - p.addr = addr; - while (nleft > 1) { - sum += *p.i++; - nleft -= 2; - } - - if (nleft == 1) { - uint8_t a = 0; - memcpy (&a, p.i, 1); - sum += ntohs (a) << 8; - } - - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - - return ~sum; -} - -void make_dhcp_packet(struct udp_dhcp_packet *packet, - const unsigned char *data, size_t length, - struct in_addr source, struct in_addr dest) -{ - struct ip *ip = &packet->ip; - struct udphdr *udp = &packet->udp; - - /* OK, this is important :) - * We copy the data to our packet and then create a small part of the - * ip structure and an invalid ip_len (basically udp length). - * We then fill the udp structure and put the checksum - * of the whole packet into the udp checksum. - * Finally we complete the ip structure and ip checksum. - * If we don't do the ordering like so then the udp checksum will be - * broken, so find another way of doing it! */ - - memcpy (&packet->dhcp, data, length); - - ip->ip_p = IPPROTO_UDP; - ip->ip_src.s_addr = source.s_addr; - if (dest.s_addr == 0) - ip->ip_dst.s_addr = INADDR_BROADCAST; - else - ip->ip_dst.s_addr = dest.s_addr; - - udp->uh_sport = htons (DHCP_CLIENT_PORT); - udp->uh_dport = htons (DHCP_SERVER_PORT); - udp->uh_ulen = htons (sizeof (*udp) + length); - ip->ip_len = udp->uh_ulen; - udp->uh_sum = checksum ((unsigned char *) packet, sizeof (*packet)); - - ip->ip_v = IPVERSION; - ip->ip_hl = 5; - ip->ip_id = 0; - ip->ip_tos = IPTOS_LOWDELAY; - ip->ip_len = htons (sizeof (*ip) + sizeof (*udp) + length); - ip->ip_id = 0; - ip->ip_off = htons (IP_DF); /* Don't fragment */ - ip->ip_ttl = IPDEFTTL; - - ip->ip_sum = checksum ((unsigned char *) ip, sizeof (*ip)); -} - -static int valid_dhcp_packet (unsigned char *data) -{ - union - { - unsigned char *data; - struct udp_dhcp_packet *packet; - } d; - uint16_t bytes; - uint16_t ipsum; - uint16_t iplen; - uint16_t udpsum; - struct in_addr source; - struct in_addr dest; - int retval = 0; - - d.data = data; - bytes = ntohs (d.packet->ip.ip_len); - ipsum = d.packet->ip.ip_sum; - iplen = d.packet->ip.ip_len; - udpsum = d.packet->udp.uh_sum; - - d.data = data; - d.packet->ip.ip_sum = 0; - if (ipsum != checksum ((unsigned char *) &d.packet->ip, - sizeof (d.packet->ip))) - { - logger (LOG_DEBUG, "bad IP header checksum, ignoring"); - retval = -1; - goto eexit; - } - - memcpy (&source, &d.packet->ip.ip_src, sizeof (d.packet->ip.ip_src)); - memcpy (&dest, &d.packet->ip.ip_dst, sizeof (d.packet->ip.ip_dst)); - memset (&d.packet->ip, 0, sizeof (d.packet->ip)); - d.packet->udp.uh_sum = 0; - - d.packet->ip.ip_p = IPPROTO_UDP; - memcpy (&d.packet->ip.ip_src, &source, sizeof (d.packet->ip.ip_src)); - memcpy (&d.packet->ip.ip_dst, &dest, sizeof (d.packet->ip.ip_dst)); - d.packet->ip.ip_len = d.packet->udp.uh_ulen; - if (udpsum && udpsum != checksum (d.data, bytes)) { - logger (LOG_ERR, "bad UDP checksum, ignoring"); - retval = -1; - } - -eexit: - d.packet->ip.ip_sum = ipsum; - d.packet->ip.ip_len = iplen; - d.packet->udp.uh_sum = udpsum; - - return retval; -} - -#if defined(BSD) || defined(__FreeBSD_kernel__) -int open_socket (interface_t *iface, int protocol) -{ - int n = 0; - int fd = -1; - char *device; - int flags; - struct ifreq ifr; - int buf = 0; - struct bpf_program pf; - - device = xmalloc (sizeof (char) * PATH_MAX); - do { - snprintf (device, PATH_MAX, "/dev/bpf%d", n++); - fd = open (device, O_RDWR); - } while (fd == -1 && errno == EBUSY); - free (device); - - if (fd == -1) { - logger (LOG_ERR, "unable to open a BPF device"); - return -1; - } - - close_on_exec (fd); - - memset (&ifr, 0, sizeof (ifr)); - strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); - if (ioctl (fd, BIOCSETIF, &ifr) == -1) { - logger (LOG_ERR, - "cannot attach interface `%s' to bpf device `%s': %s", - iface->name, device, strerror (errno)); - close (fd); - return -1; - } - - /* Get the required BPF buffer length from the kernel. */ - if (ioctl (fd, BIOCGBLEN, &buf) == -1) { - logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno)); - close (fd); - return -1; - } - iface->buffer_length = buf; - - flags = 1; - if (ioctl (fd, BIOCIMMEDIATE, &flags) == -1) { - logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno)); - close (fd); - return -1; - } - - /* Install the DHCP filter */ - if (protocol == ETHERTYPE_ARP) { - pf.bf_insns = arp_bpf_filter; - pf.bf_len = sizeof (arp_bpf_filter) - / sizeof (arp_bpf_filter[0]); - } else { - pf.bf_insns = dhcp_bpf_filter; - pf.bf_len = sizeof (dhcp_bpf_filter) - / sizeof (dhcp_bpf_filter[0]); - } - if (ioctl (fd, BIOCSETF, &pf) == -1) { - logger (LOG_ERR, "ioctl BIOCSETF: %s", strerror (errno)); - close (fd); - return -1; - } - - if (iface->fd > -1) - close (iface->fd); - iface->fd = fd; - - return fd; -} - -ssize_t send_packet (const interface_t *iface, int type, - const unsigned char *data, size_t len) -{ - ssize_t retval = -1; - struct iovec iov[2]; - - if (iface->family == ARPHRD_ETHER) { - struct ether_header hw; - memset (&hw, 0, sizeof (hw)); - memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); - hw.ether_type = htons (type); - - iov[0].iov_base = &hw; - iov[0].iov_len = sizeof (hw); - } else { - logger (LOG_ERR, "unsupported interace type %d", iface->family); - return -1; - } - iov[1].iov_base = (unsigned char *) data; - iov[1].iov_len = len; - - if ((retval = writev(iface->fd, iov, 2)) == -1) - logger (LOG_ERR, "writev: %s", strerror (errno)); - - return retval; -} - -/* BPF requires that we read the entire buffer. - * So we pass the buffer in the API so we can loop on >1 dhcp packet. */ -ssize_t get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, - size_t *buffer_len, size_t *buffer_pos) -{ - union - { - unsigned char *buffer; - struct bpf_hdr *packet; - } bpf; - - bpf.buffer = buffer; - - if (*buffer_pos < 1) { - memset (bpf.buffer, 0, iface->buffer_length); - *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length); - *buffer_pos = 0; - if (*buffer_len < 1) { - struct timespec ts; - logger (LOG_ERR, "read: %s", strerror (errno)); - ts.tv_sec = 3; - ts.tv_nsec = 0; - nanosleep (&ts, NULL); - return (-1); - } - } else - bpf.buffer += *buffer_pos; - - while (bpf.packet) { - size_t len = 0; - union - { - unsigned char *buffer; - struct ether_header *hw; - } hdr; - unsigned char *payload; - bool have_data = false; - - /* Ensure that the entire packet is in our buffer */ - if (*buffer_pos + bpf.packet->bh_hdrlen + bpf.packet->bh_caplen - > (unsigned) *buffer_len) - break; - - hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen; - payload = hdr.buffer + sizeof (*hdr.hw); - - /* If it's an ARP reply, then just send it back */ - if (hdr.hw->ether_type == htons (ETHERTYPE_ARP)) { - len = bpf.packet->bh_caplen - - sizeof (*hdr.hw); - memcpy (data, payload, len); - have_data = true; - } else { - if (valid_dhcp_packet (payload) >= 0) { - union - { - unsigned char *buffer; - struct udp_dhcp_packet *packet; - } pay; - pay.buffer = payload; - len = ntohs (pay.packet->ip.ip_len) - - sizeof (pay.packet->ip) - - sizeof (pay.packet->udp); - memcpy (data, &pay.packet->dhcp, len); - have_data = true; - } - } - - /* Update the buffer_pos pointer */ - bpf.buffer += BPF_WORDALIGN (bpf.packet->bh_hdrlen + - bpf.packet->bh_caplen); - if ((unsigned) (bpf.buffer - buffer) < *buffer_len) - *buffer_pos = bpf.buffer - buffer; - else - *buffer_pos = 0; - - if (have_data) - return len; - - if (*buffer_pos == 0) - break; - } - - /* No valid packets left, so return */ - *buffer_pos = 0; - return -1; -} - -#elif __linux__ - -int open_socket (interface_t *iface, int protocol) -{ - int fd; - union sockunion { - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_ll sll; - struct sockaddr_storage ss; - } su; - struct sock_fprog pf; - struct ifreq ifr; - int n = 1; - - /* We need to bind to a port, otherwise Linux generate ICMP messages - * that cannot contect the port when we have an address. - * We don't actually use this fd at all, instead using our packet - * filter socket. */ - if (iface->listen_fd == -1 && protocol == ETHERTYPE_IP) { - if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - } else { - memset (&su, 0, sizeof (su)); - su.sin.sin_family = AF_INET; - su.sin.sin_port = htons (DHCP_CLIENT_PORT); - if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, - &n, sizeof (n)) == -1) - logger (LOG_ERR, "SO_REUSEADDR: %s", - strerror (errno)); - if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, - &n, sizeof (n)) == -1) - logger (LOG_ERR, "SO_RCVBUF: %s", - strerror (errno)); - memset (&ifr, 0, sizeof (ifr)); - strncpy (ifr.ifr_name, iface->name, - sizeof (ifr.ifr_name)); - if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, - &ifr, sizeof (ifr)) == -1) - logger (LOG_ERR, "SO_SOBINDTODEVICE: %s", - strerror (errno)); - if (bind (fd, &su.sa, sizeof (su)) == -1) { - logger (LOG_ERR, "bind: %s", strerror (errno)); - close (fd); - } else { - iface->listen_fd = fd; - close_on_exec (fd); - } - } - } - - if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (protocol))) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - close_on_exec (fd); - - memset (&su, 0, sizeof (su)); - su.sll.sll_family = PF_PACKET; - su.sll.sll_protocol = htons (protocol); - if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) { - logger (LOG_ERR, - "if_nametoindex: no index for interface `%s'", - iface->name); - close (fd); - return (-1); - } - - /* Install the DHCP filter */ - memset (&pf, 0, sizeof (pf)); - if (protocol == ETHERTYPE_ARP) { - pf.filter = arp_bpf_filter; - pf.len = sizeof (arp_bpf_filter) / sizeof (arp_bpf_filter[0]); - } else { - pf.filter = dhcp_bpf_filter; - pf.len = sizeof (dhcp_bpf_filter) / sizeof (dhcp_bpf_filter[0]); - } - if (setsockopt (fd, SOL_SOCKET, SO_ATTACH_FILTER, - &pf, sizeof (pf)) != 0) - { - logger (LOG_ERR, "SO_ATTACH_FILTER: %s", strerror (errno)); - close (fd); - return (-1); - } - - if (bind (fd, &su.sa, sizeof (su)) == -1) { - logger (LOG_ERR, "bind: %s", strerror (errno)); - close (fd); - return (-1); - } - - if (iface->fd > -1) - close (iface->fd); - iface->fd = fd; - iface->socket_protocol = protocol; - iface->buffer_length = BUFFER_LENGTH; - - return (fd); -} - -ssize_t send_packet (const interface_t *iface, int type, - const unsigned char *data, size_t len) -{ - union sockunion { - struct sockaddr sa; - struct sockaddr_ll sll; - struct sockaddr_storage ss; - } su; - ssize_t retval; - - if (! iface) - return (-1); - - memset (&su, 0, sizeof (su)); - su.sll.sll_family = AF_PACKET; - su.sll.sll_protocol = htons (type); - - if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) { - logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", - iface->name); - return (-1); - } - - su.sll.sll_hatype = htons (iface->family); - su.sll.sll_halen = iface->hwlen; - if (iface->family == ARPHRD_INFINIBAND) - memcpy (&su.sll.sll_addr, - &ipv4_bcast_addr, sizeof (ipv4_bcast_addr)); - else - memset (&su.sll.sll_addr, 0xff, iface->hwlen); - - if ((retval = sendto (iface->fd, data, len, 0, &su.sa, - sizeof (su))) == -1) - - logger (LOG_ERR, "sendto: %s", strerror (errno)); - return (retval); -} - -/* Linux has no need for the buffer as we can read as much as we want. - * We only have the buffer listed to keep the same API. */ -ssize_t get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, - size_t *buffer_len, size_t *buffer_pos) -{ - ssize_t bytes; - union - { - unsigned char *buffer; - struct udp_dhcp_packet *packet; - } pay; - - /* We don't use the given buffer, but we need to rewind the position */ - *buffer_pos = 0; - - memset (buffer, 0, iface->buffer_length); - bytes = read (iface->fd, buffer, iface->buffer_length); - - if (bytes == -1) { - struct timespec ts; - logger (LOG_ERR, "read: %s", strerror (errno)); - ts.tv_sec = 3; - ts.tv_nsec = 0; - nanosleep (&ts, NULL); - return (-1); - } - - *buffer_len = bytes; - /* If it's an ARP reply, then just send it back */ - if (iface->socket_protocol == ETHERTYPE_ARP) { - memcpy (data, buffer, bytes); - return (bytes); - } - - if ((unsigned) bytes < (sizeof (pay.packet->ip) + - sizeof (pay.packet->udp))) - { - logger (LOG_DEBUG, "message too short, ignoring"); - return (-1); - } - - pay.buffer = buffer; - if (bytes < ntohs (pay.packet->ip.ip_len)) { - logger (LOG_DEBUG, "truncated packet, ignoring"); - return (-1); - } - - if (valid_dhcp_packet (buffer) == -1) - return (-1); - - bytes = ntohs (pay.packet->ip.ip_len) - - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)); - memcpy (data, &pay.packet->dhcp, bytes); - return (bytes); -} - -#else - #error "Platform not supported!" - #error "We currently support BPF and Linux sockets." - #error "Other platforms may work using BPF. If yours does, please let me know" - #error "so I can add it to our list." -#endif diff --git a/customdhcpcd/src/socket.h b/customdhcpcd/src/socket.h deleted file mode 100644 index bdf26d0..0000000 --- a/customdhcpcd/src/socket.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef SOCKET_H -#define SOCKET_H - -#include - -#include "dhcp.h" -#include "interface.h" - -void setup_packet_filters (void); -void make_dhcp_packet(struct udp_dhcp_packet *packet, - const unsigned char *data, size_t length, - struct in_addr source, struct in_addr dest); - -int open_socket (interface_t *iface, int protocol); -ssize_t send_packet (const interface_t *iface, int type, - const unsigned char *data, size_t len); -ssize_t get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, size_t *buffer_len, size_t *buffer_pos); -#endif diff --git a/customdhcpcd/src/version.h b/customdhcpcd/src/version.h deleted file mode 100644 index 9cf5fa4..0000000 --- a/customdhcpcd/src/version.h +++ /dev/null @@ -1 +0,0 @@ -#define VERSION "3.2.3" diff --git a/src/common/fbgui.h b/src/common/fbgui.h new file mode 100644 index 0000000..9e2c0be --- /dev/null +++ b/src/common/fbgui.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + */ + + + +#ifndef COMMON_FBGUI_H +#define COMMON_FBGUI_H + +#define DEFAULT_INTERFACE_CONF_LOCATION "/var/tmp/conf_" +#define DEFAULT_QTSOCKETADDRESS "/var/tmp/qt_c_socket_default" +#define DHCP_MESSAGE_SIZE 2048 +#define ACK_SIZE 4 + +#define DHCPCD_EXIT 9 +#define DHCPCD_ARP_TEST 10 +#define DHCPCD_CONFIGURE 11 +#define DHCPCD_WRITE 12 +#define DHCPCD_LOG 13 + +#endif // COMMON_FBGUI_H diff --git a/src/customdhcpcd/.gitignore b/src/customdhcpcd/.gitignore new file mode 100644 index 0000000..e531d2b --- /dev/null +++ b/src/customdhcpcd/.gitignore @@ -0,0 +1,5 @@ +*.o +dhcpcd +dhcpcd.8 +dhcpcd-*.bz2 +build diff --git a/src/customdhcpcd/CMakeLists.txt b/src/customdhcpcd/CMakeLists.txt new file mode 100644 index 0000000..a716a5a --- /dev/null +++ b/src/customdhcpcd/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8) + +project(customdhcpdcd) + +set(CMAKE_C_FLAGS "-lrt") + +set(CUSTOMDHCPCD_SOURCES arp.c configure.c info.c logger.c socket.c client.c discover.c interface.c logwriter.c +common.c dhcp.c duid.c ipv4ll.c signal.c) + +#file(GLOB_RECURSE CUSTOMDHCPCD_SOURCES *.c) +file(GLOB_RECURSE CUSTOMDHCPCD_HEADERS *.h) + +add_library(customdhcpcd SHARED ${CUSTOMDHCPCD_SOURCES} ${CUSTOMDHCPCD_HEADERS}) + +#add_executable(customdhcpcd ${CUSTOMDHCPCD_SOURCES}) +add_executable(cdhcpcd dhcpcd.c) +target_link_libraries(cdhcpcd customdhcpcd ) diff --git a/src/customdhcpcd/README b/src/customdhcpcd/README new file mode 100644 index 0000000..9089ec6 --- /dev/null +++ b/src/customdhcpcd/README @@ -0,0 +1,45 @@ +dhcpcd-3 - DHCP client daemon +Copyright 2006-2008 Roy Marples + + +Installation +------------ +Edit config.h to match your building requirements. + +Take special note of ENABLE_DUID and unset it if the target media is +volatile, like say a LiveCD. + +Then just make; make install + +man dhcpcd for command line options + + +Notes +----- +If you're cross compiling you may need to send HAVE_FORK=yes or HAVE_FORK=no +to the make command to avoid to automatic test. + +We try and detect how to restart ntp and ypbind, you can override this with +HAVE_INIT=no or force one of these values +OPENRC (OpenRC as used by Gentoo (forked from baselayout)) +BSDRC (BSD RC system - /etc/rc.d/ntpd restart ) +SERVICE (RedHat service command - service ntpd restart) +SLACKRC (Slackware RC system - /etc/rc.d/rc.ntpd restart) +SYSV (SYSV style - /etc/init.d/ntpd restart) + +You can change the default dir where dhcpcd stores it's .info files with +INFODIR=/var/db + +We now default to using -std=c99. For 64-bit linux, this always works, but +for 32-bit linux it requires either gnu99 or a patch to asm/types.h. +Most distros patch linux headers so this should work fine. +linux-2.6.24 finally ships with a working 32-bit header. +If your linux headers are older, or your distro hasn't patched them you can +set CSTD=gnu99 to work around this. + + +ChangeLog +--------- +We no longer supply a ChangeLog. +However, you're more than welcome to read the git commit comments at +http://git.marples.name/?p=dhcpcd/.git;a=summary diff --git a/src/customdhcpcd/arp.c b/src/customdhcpcd/arp.c new file mode 100644 index 0000000..794850c --- /dev/null +++ b/src/customdhcpcd/arp.c @@ -0,0 +1,284 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "arp.h" +#include "interface.h" +#include "logger.h" +#include "signal.h" +#include "socket.h" + +/* These are really for IPV4LL */ +#define NPROBES 3 +#define PROBE_INTERVAL 200 +#define NCLAIMS 2 +#define CLAIM_INTERVAL 200 + +/* Linux does not seem to define these handy macros */ +#ifndef ar_sha +#define ar_sha(ap) (((caddr_t) ((ap) + 1)) + 0) +#define ar_spa(ap) (((caddr_t) ((ap) + 1)) + (ap)->ar_hln) +#define ar_tha(ap) (((caddr_t) ((ap) + 1)) + (ap)->ar_hln + (ap)->ar_pln) +#define ar_tpa(ap) (((caddr_t) ((ap) + 1)) + 2 * (ap)->ar_hln + (ap)->ar_pln) +#endif + +#ifndef arphdr_len +#define arphdr_len2(ar_hln, ar_pln) (sizeof (struct arphdr) + \ + 2 * (ar_hln) + 2 * (ar_pln)) +#define arphdr_len(ap) (arphdr_len2 ((ap)->ar_hln, (ap)->ar_pln)) +#endif + +#ifdef ENABLE_ARP + +static int send_arp (const interface_t *iface, int op, struct in_addr sip, + const unsigned char *taddr, struct in_addr tip) +{ + struct arphdr *arp; + size_t arpsize = arphdr_len2 (iface->hwlen, sizeof (sip)); + caddr_t tha; + int retval; + + arp = xzalloc (arpsize); + arp->ar_hrd = htons (iface->family); + arp->ar_pro = htons (ETHERTYPE_IP); + arp->ar_hln = iface->hwlen; + arp->ar_pln = sizeof (sip); + arp->ar_op = htons (op); + memcpy (ar_sha (arp), iface->hwaddr, (size_t) arp->ar_hln); + memcpy (ar_spa (arp), &sip, (size_t) arp->ar_pln); + if (taddr) { + /* NetBSD can return NULL from ar_tha, which is probably wrong + * but we still need to deal with it */ + if (! (tha = ar_tha (arp))) { + free (arp); + errno = EINVAL; + return (-1); + } + memcpy (tha, taddr, (size_t) arp->ar_hln); + } + memcpy (ar_tpa (arp), &tip, (size_t) arp->ar_pln); + + retval = send_packet (iface, ETHERTYPE_ARP, + (unsigned char *) arp, arphdr_len (arp)); + free (arp); + return (retval); +} + +int arp_claim (interface_t *iface, struct in_addr address) +{ + struct arphdr *reply = NULL; + long timeout = 0; + unsigned char *buffer; + int retval = -1; + int nprobes = 0; + int nclaims = 0; + struct in_addr null_address; + struct pollfd fds[] = { + { -1, POLLIN, 0 }, + { -1, POLLIN, 0 } + }; + + if (! iface) + return (-1); + + if (! iface->arpable) { + logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name); + return (0); + } + + if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && + ! IN_LINKLOCAL (ntohl (address.s_addr))) + logger (LOG_INFO, + "checking %s is available on attached networks", + inet_ntoa (address)); + + if (! open_socket (iface, ETHERTYPE_ARP)) + return (-1); + + fds[0].fd = signal_fd (); + fds[1].fd = iface->fd; + + memset (&null_address, 0, sizeof (null_address)); + + buffer = xmalloc (iface->buffer_length); + reply = xmalloc (iface->buffer_length); + + for (;;) { + size_t bufpos = 0; + size_t buflen = iface->buffer_length; + int bytes; + int s = 0; + struct timeval stopat; + struct timeval now; + + /* Only poll if we have a timeout */ + if (timeout > 0) { + s = poll (fds, 2, timeout); + if (s == -1) { + if (errno == EINTR) { + if (signal_exists (NULL) == -1) { + errno = 0; + continue; + } else + break; + } + + logger (LOG_ERR, "poll: `%s'", + strerror (errno)); + break; + } + } + + /* Timed out */ + if (s == 0) { + if (nprobes < NPROBES) { + nprobes ++; + timeout = PROBE_INTERVAL; + logger (LOG_DEBUG, "sending ARP probe #%d", + nprobes); + if (send_arp (iface, ARPOP_REQUEST, + null_address, NULL, + address) == -1) + break; + + /* IEEE1394 cannot set ARP target address + * according to RFC2734 */ + if (nprobes >= NPROBES && + iface->family == ARPHRD_IEEE1394) + nclaims = NCLAIMS; + } else if (nclaims < NCLAIMS) { + nclaims ++; + timeout = CLAIM_INTERVAL; + logger (LOG_DEBUG, "sending ARP claim #%d", + nclaims); + if (send_arp (iface, ARPOP_REQUEST, + address, iface->hwaddr, + address) == -1) + break; + } else { + /* No replies, so done */ + retval = 0; + break; + } + + /* Setup our stop time */ + if (get_time (&stopat) != 0) + break; + stopat.tv_usec += timeout; + + continue; + } + + /* We maybe ARP flooded, so check our time */ + if (get_time (&now) != 0) + break; + if (timercmp (&now, &stopat, >)) { + timeout = 0; + continue; + } + + if (! fds[1].revents & POLLIN) + continue; + + memset (buffer, 0, buflen); + do { + union { + unsigned char *c; + struct in_addr *a; + } rp; + union { + unsigned char *c; + struct ether_addr *a; + } rh; + + memset (reply, 0, iface->buffer_length); + if ((bytes = get_packet (iface, (unsigned char *) reply, + buffer, + &buflen, &bufpos)) == -1) + break; + + /* Only these types are recognised */ + if (reply->ar_op != htons (ARPOP_REPLY)) + continue; + + /* Protocol must be IP. */ + if (reply->ar_pro != htons (ETHERTYPE_IP)) + continue; + if (reply->ar_pln != sizeof (address)) + continue; + if ((unsigned) bytes < sizeof (reply) + + 2 * (4 + reply->ar_hln)) + continue; + + rp.c = (unsigned char *) ar_spa (reply); + rh.c = (unsigned char *) ar_sha (reply); + + /* Ensure the ARP reply is for the our address */ + if (rp.a->s_addr != address.s_addr) + continue; + + /* Some systems send a reply back from our hwaddress, + * which is wierd */ + if (reply->ar_hln == iface->hwlen && + memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0) + continue; + + logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", + inet_ntoa (*rp.a), + hwaddr_ntoa (rh.c, (size_t) reply->ar_hln)); + retval = -1; + goto eexit; + } while (bufpos != 0); + } + +eexit: + close (iface->fd); + iface->fd = -1; + free (buffer); + free (reply); + return (retval); +} +#endif diff --git a/src/customdhcpcd/arp.h b/src/customdhcpcd/arp.h new file mode 100644 index 0000000..3b7e8ef --- /dev/null +++ b/src/customdhcpcd/arp.h @@ -0,0 +1,39 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef ARP_H +#define ARP_H + +#ifdef ENABLE_ARP +#include + +#include "interface.h" + +int arp_claim (interface_t *iface, struct in_addr address); +#endif + +#endif diff --git a/src/customdhcpcd/client.c b/src/customdhcpcd/client.c new file mode 100644 index 0000000..b007fd6 --- /dev/null +++ b/src/customdhcpcd/client.c @@ -0,0 +1,1149 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#ifdef __linux__ +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#ifdef ENABLE_ARP +# include "arp.h" +#endif +#include "client.h" +#include "configure.h" +#include "dhcp.h" +#include "dhcpcd.h" +#include "info.h" +#include "interface.h" +#ifdef ENABLE_IPV4LL +# include "ipv4ll.h" +#endif +#include "logger.h" +#include "signal.h" +#include "socket.h" + +#include "logwriter.h" + +#ifdef ENABLE_DUID +# include "duid.h" +#endif + +#ifdef ENABLE_INFO +# include "info.h" +#endif + +#ifdef THERE_IS_NO_FORK +# ifndef ENABLE_INFO + # error "Non MMU requires ENABLE_INFO to work" +# endif +#endif + +/* Some platforms don't define INFTIM */ +#ifndef INFTIM +# define INFTIM -1 +#endif + +/* This is out mini timeout. + * Basically we resend the last request every TIMEOUT_MINI seconds. */ +#define TIMEOUT_MINI 3 +/* Except for an infinite timeout. We keep adding TIMEOUT_MINI to + * ourself until TIMEOUT_MINI_INF is reached. */ +#define TIMEOUT_MINI_INF 60 + +#define STATE_INIT 0 +#define STATE_REQUESTING 1 +#define STATE_BOUND 2 +#define STATE_RENEWING 3 +#define STATE_REBINDING 4 +#define STATE_REBOOT 5 +#define STATE_RENEW_REQUESTED 6 +#define STATE_RELEASED 7 + +/* We should define a maximum for the NAK exponential backoff */ +#define NAKOFF_MAX 60 + +#define SOCKET_CLOSED 0 +#define SOCKET_OPEN 1 + +/* Indexes for pollfds */ +#define POLLFD_SIGNAL 0 +#define POLLFD_IFACE 1 + +typedef struct _state { + int *pidfd; + bool forked; + int state; + uint32_t xid; + dhcp_t *dhcp; + int socket; + interface_t *interface; + time_t start; + time_t last_sent; + time_t last_type; + long timeout; + time_t nakoff; + bool daemonised; + bool persistent; + unsigned char *buffer; + size_t buffer_len; + size_t buffer_pos; +} state_t; + +static pid_t daemonise (int *pidfd) +{ + pid_t pid; + sigset_t full; + sigset_t old; +#ifdef THERE_IS_NO_FORK + char **argv; + int i; +#endif + + sigfillset (&full); + sigprocmask (SIG_SETMASK, &full, &old); + +#ifndef THERE_IS_NO_FORK + logger (LOG_DEBUG, "forking to background"); + switch (pid = fork()) { + case -1: + logger (LOG_ERR, "fork: %s", strerror (errno)); + exit (EXIT_FAILURE); + /* NOT REACHED */ + case 0: + setsid (); + close_fds (); + break; + default: + /* Reset our signals as we're the parent about to exit. */ + signal_reset (); + break; + } +#else + logger (LOG_INFO, "forking to background"); + + /* We need to add --daemonise to our options */ + argv = xmalloc (sizeof (char *) * (dhcpcd_argc + 4)); + argv[0] = dhcpcd; + for (i = 1; i < dhcpcd_argc; i++) + argv[i] = dhcpcd_argv[i]; + argv[i] = (char *) "--daemonised"; + if (dhcpcd_skiproutes) { + argv[++i] = (char *) "--skiproutes"; + argv[++i] = dhcpcd_skiproutes; + } + argv[i + 1] = NULL; + + switch (pid = vfork ()) { + case -1: + logger (LOG_ERR, "vfork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + case 0: + signal_reset (); + sigprocmask (SIG_SETMASK, &old, NULL); + execvp (dhcpcd, argv); + logger (LOG_ERR, "execl `%s': %s", dhcpcd, + strerror (errno)); + _exit (EXIT_FAILURE); + } + + free (argv); +#endif + + /* Done with the fd now */ + if (pid != 0) { + writepid (*pidfd, pid); + close (*pidfd); + *pidfd = -1; + + } + + sigprocmask (SIG_SETMASK, &old, NULL); + return (pid); +} + +#ifdef ENABLE_INFO +static bool get_old_lease (state_t *state, const options_t *options) +{ + interface_t *iface = state->interface; + dhcp_t *dhcp = state->dhcp; + struct timeval tv; + unsigned int offset = 0; + + if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) + logger (LOG_INFO, "trying to use old lease in `%s'", + iface->infofile); + if (! read_info (iface, dhcp)) + return (false); + + /* Vitaly important we remove the server information here */ + memset (&dhcp->serveraddress, 0, sizeof (dhcp->serveraddress)); + memset (dhcp->servername, 0, sizeof (dhcp->servername)); + +#ifdef ENABLE_ARP + /* Check that no-one is using the address */ + if ((options->dolastlease || + (IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && + (! options->doipv4ll || + arp_claim (iface, dhcp->address))))) + { + memset (&dhcp->address, 0, sizeof (dhcp->address)); + memset (&dhcp->netmask, 0, sizeof (dhcp->netmask)); + memset (&dhcp->broadcast, 0, sizeof (dhcp->broadcast)); + return (false); + } + + /* Ok, lets use this */ + if (IN_LINKLOCAL (dhcp->address.s_addr)) + return (true); +#endif + + /* Ensure that we can still use the lease */ + if (gettimeofday (&tv, NULL) == -1) { + logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); + return (false); + } + + offset = tv.tv_sec - dhcp->leasedfrom; + if (dhcp->leasedfrom && + tv.tv_sec - dhcp->leasedfrom > dhcp->leasetime) + { + logger (LOG_ERR, "lease expired %u seconds ago", + offset + dhcp->leasetime); + return (false); + } + + if (dhcp->leasedfrom == 0) + offset = 0; + state->timeout = dhcp->renewaltime - offset; + iface->start_uptime = uptime (); + return (true); +} +#endif + +#ifdef THERE_IS_NO_FORK +static void remove_skiproutes (dhcp_t *dhcp, interface_t *iface) +{ + int i = -1; + route_t *route; + route_t *newroute; + + free_route (iface->previous_routes); + iface->previous_routes = NULL; + + NSTAILQ_FOREACH (route, dhcp->routes, entries) { + i++; + + /* Check that we did add this route or not */ + if (dhcpcd_skiproutes) { + char *sk = xstrdup (dhcpcd_skiproutes); + char *skp = sk; + char *token; + bool found = false; + + while ((token = strsep (&skp, ","))) { + if (isdigit (*token) && atoi (token) == i) { + found = true; + break; + } + } + free (sk); + if (found) + continue; + } + + if (! iface->previous_routes) { + iface->previous_routes = xmalloc (sizeof (*iface->previous_routes)); + STAILQ_INIT (iface->previous_routes); + } + + newroute = xmalloc (sizeof (*newroute)); + memcpy (newroute, route, sizeof (*newroute)); + STAILQ_INSERT_TAIL (iface->previous_routes, newroute, entries); + } + + /* We no longer need this argument */ + free (dhcpcd_skiproutes); + dhcpcd_skiproutes = NULL; +} +#endif + +static bool client_setup (state_t *state, const options_t *options) +{ + dhcp_t *dhcp = state->dhcp; + interface_t *iface = state->interface; + + state->state = STATE_INIT; + state->last_type = DHCP_DISCOVER; + state->nakoff = 1; + state->daemonised = options->daemonised; + state->persistent = options->persistent; + + if (options->request_address.s_addr == 0 && + (options->doinform || options->dorequest || options->daemonised)) + { +#ifdef ENABLE_INFO + if (! get_old_lease (state, options)) +#endif + { + free (dhcp); + return (false); + } + state->timeout = 0; + + if (! options->daemonised && + IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) + { + logger (LOG_ERR, "cannot request a link local address"); + return (false); + } +#ifdef THERE_IS_NO_FORK + if (options->daemonised) { + state->state = STATE_BOUND; + state->timeout = dhcp->renewaltime; + iface->previous_address = dhcp->address; + iface->previous_netmask = dhcp->netmask; + remove_skiproutes (dhcp, iface); + } +#endif + + } else { + dhcp->address = options->request_address; + dhcp->netmask = options->request_netmask; + if (dhcp->netmask.s_addr == 0) + dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); + dhcp->broadcast.s_addr = dhcp->address.s_addr | + ~dhcp->netmask.s_addr; + } + + /* Remove all existing addresses. + * After all, we ARE a DHCP client whose job it is to configure the + * interface. We only do this on start, so persistent addresses + * can be added afterwards by the user if needed. */ + if (! options->test && ! options->daemonised) { + if (! options->doinform) { + flush_addresses (iface->name); + } else { + /* The inform address HAS to be configured for it to + * work with most DHCP servers */ + if (options->doinform && + has_address (iface->name, dhcp->address) < 1) + { + add_address (iface->name, dhcp->address, + dhcp->netmask, dhcp->broadcast); + iface->previous_address = dhcp->address; + iface->previous_netmask = dhcp->netmask; + } + } + } + + if (*options->clientid) { + /* Attempt to see if the ClientID is a hardware address */ + iface->clientid_len = hwaddr_aton (NULL, options->clientid); + if (iface->clientid_len) { + iface->clientid = xmalloc (iface->clientid_len); + hwaddr_aton (iface->clientid, options->clientid); + } else { + /* Nope, so mark it as-is */ + iface->clientid_len = strlen (options->clientid) + 1; + iface->clientid = xmalloc (iface->clientid_len); + *iface->clientid = '\0'; + memcpy (iface->clientid + 1, + options->clientid, iface->clientid_len - 1); + } + } else { +#ifdef ENABLE_DUID + unsigned char *duid = NULL; + size_t duid_len = 0; + + if (options->doduid) { + duid = xmalloc (DUID_LEN); + duid_len = get_duid (duid, iface); + } + + if (duid_len > 0) { + logger (LOG_INFO, "DUID = %s", hwaddr_ntoa (duid, duid_len)); + + iface->clientid_len = duid_len + 5; + iface->clientid = xmalloc (iface->clientid_len); + *iface->clientid = 255; /* RFC 4361 */ + + /* IAID is 4 bytes, so if the iface name is 4 bytes use it */ + if (strlen (iface->name) == 4) { + memcpy (iface->clientid + 1, iface->name, 4); + } else { + /* Name isn't 4 bytes, so use the index */ + uint32_t ul = htonl (if_nametoindex (iface->name)); + memcpy (iface->clientid + 1, &ul, 4); + } + + memcpy (iface->clientid + 5, duid, duid_len); + free (duid); + } else { +#else + { +#endif + iface->clientid_len = iface->hwlen + 1; + iface->clientid = xmalloc (iface->clientid_len); + *iface->clientid = iface->family; + memcpy (iface->clientid + 1, iface->hwaddr, iface->hwlen); + } + } + + return (true); +} + +static bool do_socket (state_t *state, int mode) +{ + if (state->interface->fd >= 0) + close (state->interface->fd); +#ifdef __linux + if (mode == SOCKET_CLOSED && state->interface->listen_fd >= 0) { + close (state->interface->listen_fd); + state->interface->listen_fd = -1; + } +#endif + + state->interface->fd = -1; + if (mode == SOCKET_OPEN) + if (open_socket (state->interface, ETHERTYPE_IP) == -1) + return (false); + state->socket = mode; + return (true); +} + +static bool _send_message (state_t *state, int type, const options_t *options) +{ + ssize_t retval; + + state->last_type = type; + state->last_sent = uptime (); + logSendToQt(type); + retval = send_message (state->interface, state->dhcp, state->xid, + type, options); + return (retval == -1 ? false : true); +} + +static void drop_config (state_t *state, const options_t *options) +{ + if (! state->persistent) + configure (options, state->interface, state->dhcp, false); + + free_dhcp (state->dhcp); + memset (state->dhcp, 0, sizeof (*state->dhcp)); +} + +static int wait_for_packet (struct pollfd *fds, state_t *state, + const options_t *options) +{ + dhcp_t *dhcp = state->dhcp; + interface_t *iface = state->interface; + int timeout = 0; + int retval = 0; + + if (! (state->timeout > 0 || + (options->timeout == 0 && + (state->state != STATE_INIT || state->xid)))) { + /* We need to zero our signal fd, otherwise we will block + * trying to read a signal. */ + fds[POLLFD_SIGNAL].revents = 0; + return (0); + } + + fds[POLLFD_IFACE].fd = iface->fd; + + if ((options->timeout == 0 && state->xid) || + (dhcp->leasetime == (unsigned) -1 && + state->state == STATE_BOUND)) + { + logger (LOG_DEBUG, "waiting for infinity"); + while (retval == 0) { + if (iface->fd == -1) + retval = poll (fds, 1, INFTIM); + else { + /* Slow down our requests */ + if (timeout < TIMEOUT_MINI_INF) + timeout += TIMEOUT_MINI; + else if (timeout > TIMEOUT_MINI_INF) + timeout = TIMEOUT_MINI_INF; + + retval = poll (fds, 2, timeout * 1000); + if (retval == -1 && errno == EINTR) { + /* If interupted, continue as normal as + * the signal will be delivered down + * the pipe */ + retval = 0; + continue; + } + if (retval == 0) + _send_message (state, state->last_type, + options); + } + } + + return (retval); + } + + /* Resend our message if we're getting loads of packets. + * As we use BPF or LPF, we shouldn't hit this as much, but it's + * still nice to have. */ + if (iface->fd > -1 && uptime () - state->last_sent >= TIMEOUT_MINI) + _send_message (state, state->last_type, options); + + logger (LOG_DEBUG, "waiting for %ld seconds", + (unsigned long) state->timeout); + /* If we're waiting for a reply, then we re-send the last + * DHCP request periodically in-case of a bad line */ + retval = 0; + while (state->timeout > 0 && retval == 0) { + if (iface->fd == -1) + timeout = (int) state->timeout; + else { + timeout = TIMEOUT_MINI; + if (state->timeout < timeout) + timeout = (int) state->timeout; + } + timeout *= 1000; + state->start = uptime (); + retval = poll (fds, iface->fd == -1 ? 1 : 2, timeout); + state->timeout -= uptime () - state->start; + if (retval == -1 && errno == EINTR) { + /* If interupted, continue as normal as the signal + * will be delivered down the pipe */ + retval = 0; + continue; + } + if (retval == 0 && iface->fd != -1 && state->timeout > 0) + _send_message (state, state->last_type, options); + } + + return (retval); +} + +static bool handle_signal (int sig, state_t *state, const options_t *options) +{ + switch (sig) { + case SIGINT: + logger (LOG_INFO, "received SIGINT, stopping"); + return (false); + case SIGTERM: + logger (LOG_INFO, "received SIGTERM, stopping"); + return (false); + + case SIGALRM: + logger (LOG_INFO, "received SIGALRM, renewing lease"); + switch (state->state) { + case STATE_BOUND: + case STATE_RENEWING: + case STATE_REBINDING: + state->state = STATE_RENEW_REQUESTED; + break; + case STATE_RENEW_REQUESTED: + case STATE_REQUESTING: + case STATE_RELEASED: + state->state = STATE_INIT; + break; + } + state->timeout = 0; + state->xid = 0; + return (true); + + case SIGHUP: + if (state->state != STATE_BOUND && + state->state != STATE_RENEWING && + state->state != STATE_REBINDING) + { + logger (LOG_ERR, + "received SIGHUP, but we no have lease to release"); + return (false); + } + + logger (LOG_INFO, "received SIGHUP, releasing lease"); + if (! IN_LINKLOCAL (ntohl (state->dhcp->address.s_addr))) { + do_socket (state, SOCKET_OPEN); + state->xid = (uint32_t) random (); + if ((open_socket (state->interface, false)) >= 0) { + _send_message (state, DHCP_RELEASE, options); + } + do_socket (state, SOCKET_CLOSED); + } + unlink (state->interface->infofile); + return (false); + + default: + logger (LOG_ERR, + "received signal %d, but don't know what to do with it", + sig); + } + + return (false); +} + +static int handle_timeout (state_t *state, const options_t *options) +{ + dhcp_t *dhcp = state->dhcp; + interface_t *iface = state->interface; + + /* No NAK, so reset the backoff */ + state->nakoff = 1; + + if (state->state == STATE_INIT && state->xid != 0) { + if (iface->previous_address.s_addr != 0 && + ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && + ! options->doinform) + { + logger (LOG_ERR, "lost lease"); + if (! options->persistent) + drop_config (state, options); + } else if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) + logger (LOG_ERR, "timed out"); + + do_socket (state, SOCKET_CLOSED); + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + +#ifdef ENABLE_INFO + if (! options->test && + (options->doipv4ll || options->dolastlease)) + { + errno = 0; + if (! get_old_lease (state, options)) + { + if (errno == EINTR) + return (0); + if (options->dolastlease) + return (-1); + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + } else if (errno == EINTR) + return (0); + } +#endif + +#ifdef ENABLE_IPV4LL + if (! options->test && options->doipv4ll && + (! dhcp->address.s_addr || + (! IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && + ! options->dolastlease))) + { + logger (LOG_INFO, "probing for an IPV4LL address"); + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + if (ipv4ll_get_address (iface, dhcp) == -1) { + if (! state->daemonised) + return (-1); + + /* start over */ + state->xid = 0; + return (0); + } + state->timeout = dhcp->renewaltime; + } +#endif + +#if defined (ENABLE_INFO) || defined (ENABLE_IPV4LL) + if (dhcp->address.s_addr) { + if (! state->daemonised && + IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) + logger (LOG_WARNING, "using IPV4LL address %s", + inet_ntoa (dhcp->address)); + if (configure (options, iface, dhcp, true) == -1 && + ! state->daemonised) + return (-1); + + state->state = STATE_BOUND; + if (! state->daemonised && options->daemonise) { + switch (daemonise (state->pidfd)) { + case -1: + return (-1); + case 0: + state->daemonised = true; + return (0); + default: + state->persistent = true; + state->forked = true; + return (-1); + } + } + + state->timeout = dhcp->renewaltime; + state->xid = 0; + return (0); + } +#endif + + if (! state->daemonised) + return (-1); + } + + switch (state->state) { + case STATE_INIT: + state->xid = (uint32_t) random (); + do_socket (state, SOCKET_OPEN); + state->timeout = options->timeout; + iface->start_uptime = uptime (); + if (dhcp->address.s_addr == 0) { + if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) + logger (LOG_INFO, "broadcasting for a lease"); + _send_message (state, DHCP_DISCOVER, options); + } else if (options->doinform) { + logger (LOG_INFO, "broadcasting inform for %s", + inet_ntoa (dhcp->address)); + _send_message (state, DHCP_INFORM, options); + state->state = STATE_REQUESTING; + } else { + logger (LOG_INFO, "broadcasting for a lease of %s", + inet_ntoa (dhcp->address)); + _send_message (state, DHCP_REQUEST, options); + state->state = STATE_REQUESTING; + } + + break; + case STATE_BOUND: + case STATE_RENEW_REQUESTED: + if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) { + memset (&dhcp->address, 0, sizeof (dhcp->address)); + state->state = STATE_INIT; + state->xid = 0; + break; + } + state->state = STATE_RENEWING; + state->xid = (uint32_t) random (); + /* FALLTHROUGH */ + case STATE_RENEWING: + iface->start_uptime = uptime (); + logger (LOG_INFO, "renewing lease of %s", inet_ntoa + (dhcp->address)); + do_socket (state, SOCKET_OPEN); + _send_message (state, DHCP_REQUEST, options); + state->timeout = dhcp->rebindtime - dhcp->renewaltime; + state->state = STATE_REBINDING; + break; + case STATE_REBINDING: + logger (LOG_ERR, "lost lease, attemping to rebind"); + memset (&dhcp->address, 0, sizeof (dhcp->address)); + do_socket (state, SOCKET_OPEN); + if (state->xid == 0) + state->xid = (uint32_t) random (); + dhcp->serveraddress.s_addr = 0; + _send_message (state, DHCP_REQUEST, options); + state->timeout = dhcp->leasetime - dhcp->rebindtime; + state->state = STATE_REQUESTING; + break; + case STATE_REQUESTING: + state->state = STATE_INIT; + do_socket (state, SOCKET_CLOSED); + state->timeout = 0; + break; + + case STATE_RELEASED: + dhcp->leasetime = 0; + break; + } + + return (0); +} + + +static int handle_dhcp (state_t *state, int type, const options_t *options) +{ + struct timespec ts; + interface_t *iface = state->interface; + dhcp_t *dhcp = state->dhcp; + + /* We should restart on a NAK */ + if (type == DHCP_NAK) { + logger (LOG_INFO, "received NAK: %s", dhcp->message); + logToQt(LOG_INFO, DHCP_NAK, ""); + state->state = STATE_INIT; + state->timeout = 0; + state->xid = 0; + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + + /* If we constantly get NAKS then we should slowly back off */ + if (state->nakoff > 0) { + logger (LOG_DEBUG, "sleeping for %ld seconds", + (long) state->nakoff); + ts.tv_sec = state->nakoff; + ts.tv_nsec = 0; + state->nakoff *= 2; + if (state->nakoff > NAKOFF_MAX) + state->nakoff = NAKOFF_MAX; + nanosleep (&ts, NULL); + } + + return (0); + } + + /* No NAK, so reset the backoff */ + state->nakoff = 1; + + if (type == DHCP_OFFER && state->state == STATE_INIT) { + char *addr = strdup (inet_ntoa (dhcp->address)); + if (dhcp->servername[0]) + logger (LOG_INFO, "offered %s from %s `%s'", + addr, inet_ntoa (dhcp->serveraddress), + dhcp->servername); + else + logger (LOG_INFO, "offered %s from %s", + addr, inet_ntoa (dhcp->serveraddress)); + free (addr); + + logToQt(LOG_INFO, DHCP_OFFER, ""); + +#ifdef ENABLE_INFO + if (options->test) { + write_info (iface, dhcp, options, false); + errno = 0; + return (-1); + } +#endif + + _send_message (state, DHCP_REQUEST, options); + state->state = STATE_REQUESTING; + + return (0); + } + + if (type == DHCP_OFFER) { + logger (LOG_INFO, "got subsequent offer of %s, ignoring ", + inet_ntoa (dhcp->address)); + return (0); + } + + /* We should only be dealing with acks */ + if (type != DHCP_ACK) { + logger (LOG_ERR, "%d not an ACK or OFFER", type); + return (0); + } + + /* if we are here, than we received an ACK and can go on with configuration */ + logToQt(LOG_INFO, DHCP_ACK, ""); + + switch (state->state) { + case STATE_RENEW_REQUESTED: + case STATE_REQUESTING: + case STATE_RENEWING: + case STATE_REBINDING: + break; + default: + logger (LOG_ERR, "wrong state %d", state->state); + } + + do_socket (state, SOCKET_CLOSED); + +#ifdef ENABLE_ARP + if (options->doarp && iface->previous_address.s_addr != + dhcp->address.s_addr) + { + errno = 0; + logToQt(LOG_INFO, DHCPCD_ARP_TEST, ""); + if (arp_claim (iface, dhcp->address)) { + do_socket (state, SOCKET_OPEN); + _send_message (state, DHCP_DECLINE, options); + do_socket (state, SOCKET_CLOSED); + + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + state->xid = 0; + state->timeout = 0; + state->state = STATE_INIT; + + /* RFC 2131 says that we should wait for 10 seconds + * before doing anything else */ + logger (LOG_INFO, "sleeping for 10 seconds"); + ts.tv_sec = 10; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); + return (0); + } else if (errno == EINTR) + return (0); + } +#endif + + if (options->doinform) { + if (options->request_address.s_addr != 0) + dhcp->address = options->request_address; + else + dhcp->address = iface->previous_address; + + logger (LOG_INFO, "received approval for %s", + inet_ntoa (dhcp->address)); + if (iface->previous_netmask.s_addr != dhcp->netmask.s_addr) { + add_address (iface->name, dhcp->address, + dhcp->netmask, dhcp->broadcast); + iface->previous_netmask.s_addr = dhcp->netmask.s_addr; + } + state->timeout = options->leasetime; + if (state->timeout == 0) + state->timeout = DEFAULT_LEASETIME; + state->state = STATE_INIT; + } else if (dhcp->leasetime == (unsigned) -1) { + dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime; + state->timeout = 1; /* So we wait for infinity */ + logger (LOG_INFO, "leased %s for infinity", + inet_ntoa (dhcp->address)); + state->state = STATE_BOUND; + } else { + if (! dhcp->leasetime) { + dhcp->leasetime = DEFAULT_LEASETIME; + logger(LOG_INFO, + "no lease time supplied, assuming %d seconds", + dhcp->leasetime); + } + logger (LOG_INFO, "leased %s for %u seconds", + inet_ntoa (dhcp->address), dhcp->leasetime); + + if (dhcp->rebindtime >= dhcp->leasetime) { + dhcp->rebindtime = (dhcp->leasetime * 0.875); + logger (LOG_ERR, + "rebind time greater than lease " + "time, forcing to %u seconds", + dhcp->rebindtime); + } + + if (dhcp->renewaltime > dhcp->rebindtime) { + dhcp->renewaltime = (dhcp->leasetime * 0.5); + logger (LOG_ERR, + "renewal time greater than rebind time, " + "forcing to %u seconds", + dhcp->renewaltime); + } + + if (! dhcp->renewaltime) { + dhcp->renewaltime = (dhcp->leasetime * 0.5); + logger (LOG_INFO, + "no renewal time supplied, assuming %d seconds", + dhcp->renewaltime); + } else + logger (LOG_DEBUG, "renew in %u seconds", + dhcp->renewaltime); + + if (! dhcp->rebindtime) { + dhcp->rebindtime = (dhcp->leasetime * 0.875); + logger (LOG_INFO, + "no rebind time supplied, assuming %d seconds", + dhcp->rebindtime); + } else + logger (LOG_DEBUG, "rebind in %u seconds", + dhcp->rebindtime); + + state->timeout = dhcp->renewaltime; + state->state = STATE_BOUND; + } + + state->xid = 0; + + logToQt(LOG_INFO, DHCPCD_CONFIGURE, ""); + if (configure (options, iface, dhcp, true) == -1 && + ! state->daemonised) + return (-1); + + if (! state->daemonised && options->daemonise) { + switch (daemonise (state->pidfd)) { + case 0: + state->daemonised = true; + return (0); + case -1: + return (-1); + default: + state->persistent = true; + state->forked = true; + return (-1); + } + } + + return (0); +} + +static int handle_packet (state_t *state, const options_t *options) +{ + interface_t *iface = state->interface; + bool valid = false; + int type; + struct dhcp_t *new_dhcp; + dhcpmessage_t message; + + /* Allocate our buffer space for BPF. + * We cannot do this until we have opened our socket as we don't + * know how much of a buffer we need until then. */ + if (! state->buffer) + state->buffer = xmalloc (iface->buffer_length); + state->buffer_len = iface->buffer_length; + state->buffer_pos = 0; + + /* We loop through until our buffer is empty. + * The benefit is that if we get >1 DHCP packet in our buffer and + * the first one fails for any reason, we can use the next. */ + + memset (&message, 0, sizeof (message)); + new_dhcp = xmalloc (sizeof (*new_dhcp)); + + do { + if (get_packet (iface, (unsigned char *) &message, + state->buffer, + &state->buffer_len, &state->buffer_pos) == -1) + break; + + if (state->xid != message.xid) { + logger (LOG_DEBUG, + "ignoring packet with xid 0x%x as it's not ours (0x%x)", + message.xid, state->xid); + continue; + } + + logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid); + memset (new_dhcp, 0, sizeof (*new_dhcp)); + type = parse_dhcpmessage (new_dhcp, &message); + if (type == -1) { + logger (LOG_ERR, "failed to parse packet"); + free_dhcp (new_dhcp); + /* We don't abort on this, so return zero */ + return (0); + } + + /* If we got here then the DHCP packet is valid and appears to + * be for us, so let's clear the buffer as we don't care about + * any more DHCP packets at this point. */ + valid = true; + break; + } while (state->buffer_pos != 0); + + /* No packets for us, so wait until we get one */ + if (! valid) { + free (new_dhcp); + return (0); + } + + /* new_dhcp is now our master DHCP message */ + free_dhcp (state->dhcp); + free (state->dhcp); + state->dhcp = new_dhcp; + new_dhcp = NULL; + + return (handle_dhcp (state, type, options)); +} + +int dhcp_run (const options_t *options, int *pidfd) +{ + interface_t *iface; + state_t *state = NULL; + struct pollfd fds[] = { + { -1, POLLIN, 0 }, + { -1, POLLIN, 0 } + }; + int retval = -1; + int sig; + + if (! options) + return (-1); + + /*read_interface : defined in interface.c*/ + iface = read_interface (options->interface, options->metric); + if (! iface) + goto eexit; + + state = xzalloc (sizeof (*state)); + state->dhcp = xzalloc (sizeof (*state->dhcp)); + state->pidfd = pidfd; + state->interface = iface; + + if (! client_setup (state, options)) + goto eexit; + + if (signal_init () == -1) + goto eexit; + if (signal_setup () == -1) + goto eexit; + + fds[POLLFD_SIGNAL].fd = signal_fd (); + + for (;;) { + retval = wait_for_packet (fds, state, options); + + /* We should always handle our signals first */ + if ((sig = (signal_read (&fds[POLLFD_SIGNAL]))) != -1) { + if (handle_signal (sig, state, options)) + retval = 0; + else + retval = -1; + } else if (retval == 0) + retval = handle_timeout (state, options); + else if (retval > 0 && + state->socket != SOCKET_CLOSED && + fds[POLLFD_IFACE].revents & POLLIN) + retval = handle_packet (state, options); + else if (retval == -1 && errno == EINTR) { + /* The interupt will be handled above */ + retval = 0; + } else { + logger (LOG_ERR, "poll: %s", strerror (errno)); + retval = -1; + } + + if (retval != 0) + break; + } + +eexit: + if (iface) { + do_socket (state, SOCKET_CLOSED); + drop_config (state, options); + free_route (iface->previous_routes); + free (iface->clientid); + free (iface); + } + + if (state) { + if (state->forked) + retval = 0; + + if (state->daemonised) + unlink (options->pidfile); + + free_dhcp (state->dhcp); + free (state->dhcp); + free (state->buffer); + free (state); + } + + return (retval); +} diff --git a/src/customdhcpcd/client.h b/src/customdhcpcd/client.h new file mode 100644 index 0000000..fa6ea9b --- /dev/null +++ b/src/customdhcpcd/client.h @@ -0,0 +1,35 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CLIENT_H +#define CLIENT_H + +#include "dhcpcd.h" + +int dhcp_run (const options_t *options, int *pidfd); + +#endif diff --git a/src/customdhcpcd/common.c b/src/customdhcpcd/common.c new file mode 100644 index 0000000..99471bc --- /dev/null +++ b/src/customdhcpcd/common.c @@ -0,0 +1,249 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "logger.h" + +/* Handy routine to read very long lines in text files. + * This means we read the whole line and avoid any nasty buffer overflows. */ +char *get_line (FILE *fp) +{ + char *line = NULL; + char *p; + size_t len = 0; + size_t last = 0; + + if (feof (fp)) + return (NULL); + + do { + len += BUFSIZ; + line = xrealloc (line, sizeof (char) * len); + p = line + last; + memset (p, 0, BUFSIZ); + fgets (p, BUFSIZ, fp); + last += strlen (p); + } while (! feof (fp) && line[last - 1] != '\n'); + + /* Trim the trailing newline */ + if (*line && line[--last] == '\n') + line[last] = '\0'; + + return (line); +} + +/* OK, this should be in dhcpcd.c + * It's here to make dhcpcd more readable */ +#ifndef HAVE_SRANDOMDEV +void srandomdev (void) +{ + int fd; + unsigned long seed; + + fd = open ("/dev/urandom", 0); + if (fd == -1 || read (fd, &seed, sizeof (seed)) == -1) { + logger (LOG_WARNING, "Could not read from /dev/urandom: %s", + strerror (errno)); + seed = time (0); + } + if (fd >= 0) + close(fd); + + srandom (seed); +} +#endif + +/* strlcpy is nice, shame glibc does not define it */ +#ifndef HAVE_STRLCPY +size_t strlcpy (char *dst, const char *src, size_t size) +{ + const char *s = src; + size_t n = size; + + if (n && --n) + do { + if (! (*dst++ = *src++)) + break; + } while (--n); + + if (! n) { + if (size) + *dst = '\0'; + while (*src++); + } + + return (src - s - 1); +} +#endif + +/* Close our fd's */ +int close_fds (void) +{ + int fd; + + if ((fd = open ("/dev/null", O_RDWR)) == -1) { + logger (LOG_ERR, "open `/dev/null': %s", strerror (errno)); + return (-1); + } + + dup2 (fd, fileno (stdin)); + dup2 (fd, fileno (stdout)); + dup2 (fd, fileno (stderr)); + if (fd > 2) + close (fd); + return (0); +} + +int close_on_exec (int fd) +{ + int flags; + + if ((flags = fcntl (fd, F_GETFD, 0)) == -1 + || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1) + { + logger (LOG_ERR, "fcntl: %s", strerror (errno)); + return (-1); + } + return (0); +} + +/* Handy function to get the time. + * We only care about time advancements, not the actual time itself + * Which is why we use CLOCK_MONOTONIC, but it is not available on all + * platforms. + */ +int get_time (struct timeval *tp) +{ +#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC) + struct timespec ts; + static clockid_t posix_clock; + static int posix_clock_set = 0; + + if (! posix_clock_set) { + if (sysconf (_SC_MONOTONIC_CLOCK) >= 0) + posix_clock = CLOCK_MONOTONIC; + else + posix_clock = CLOCK_REALTIME; + posix_clock_set = 1; + } + + if (clock_gettime (posix_clock, &ts) == -1) { + logger (LOG_ERR, "clock_gettime: %s", strerror (errno)); + return (-1); + } + + tp->tv_sec = ts.tv_sec; + tp->tv_usec = ts.tv_nsec / 1000; + return (0); +#else + if (gettimeofday (tp, NULL) == -1) { + logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); + return (-1); + } + return (0); +#endif +} + +time_t uptime (void) +{ + struct timeval tp; + + if (get_time (&tp) == -1) + return (-1); + + return (tp.tv_sec); +} + +void writepid (int fd, pid_t pid) +{ + char spid[16]; + if (ftruncate (fd, (off_t) 0) == -1) { + logger (LOG_ERR, "ftruncate: %s", strerror (errno)); + } else { + ssize_t len; + snprintf (spid, sizeof (spid), "%u", pid); + len = pwrite (fd, spid, strlen (spid), (off_t) 0); + if (len != (ssize_t) strlen (spid)) + logger (LOG_ERR, "pwrite: %s", strerror (errno)); + } +} + +void *xmalloc (size_t s) +{ + void *value = malloc (s); + + if (value) + return (value); + + logger (LOG_ERR, "memory exhausted"); + + exit (EXIT_FAILURE); + /* NOTREACHED */ +} + +void *xzalloc (size_t s) +{ + void *value = xmalloc (s); + memset (value, 0, s); + return (value); +} + +void *xrealloc (void *ptr, size_t s) +{ + void *value = realloc (ptr, s); + + if (value) + return (value); + + logger (LOG_ERR, "memory exhausted"); + exit (EXIT_FAILURE); + /* NOTREACHED */ +} + +char *xstrdup (const char *str) +{ + char *value; + + if (! str) + return (NULL); + + if ((value = strdup (str))) + return (value); + + logger (LOG_ERR, "memory exhausted"); + exit (EXIT_FAILURE); + /* NOTREACHED */ +} diff --git a/src/customdhcpcd/common.h b/src/customdhcpcd/common.h new file mode 100644 index 0000000..46f1886 --- /dev/null +++ b/src/customdhcpcd/common.h @@ -0,0 +1,68 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef COMMON_H +#define COMMON_H + +/* string.h pulls in features.h so the below define checks work */ +#include +#include +#include + +#if __GNUC__ > 2 || defined(__INTEL_COMPILER) +# define _unused __attribute__((__unused__)) +#else +# define _unused +#endif + +#define HAVE_STRLCPY +/* Only GLIBC doesn't support strlcpy */ +#ifdef __GLIBC__ +# if ! defined(__UCLIBC__) && ! defined (__dietlibc__) +# undef HAVE_STRLCPY +size_t strlcpy (char *dst, const char *src, size_t size); +# endif +#endif + +#define HAVE_SRANDOMDEV +#if defined(__GLIBC__) || defined(__NetBSD__) +# undef HAVE_SRANDOMDEV +void srandomdev (void); +#endif + +int close_fds (void); +int close_on_exec (int fd); +char *get_line (FILE *fp); +int get_time (struct timeval *tp); +time_t uptime (void); +void writepid (int fd, pid_t pid); +void *xrealloc (void *ptr, size_t size); +void *xmalloc (size_t size); +void *xzalloc (size_t size); +char *xstrdup (const char *str); + +#endif diff --git a/src/customdhcpcd/config.h b/src/customdhcpcd/config.h new file mode 100644 index 0000000..2c0991b --- /dev/null +++ b/src/customdhcpcd/config.h @@ -0,0 +1,133 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +/* You can enable/disable various chunks of optional code here. + * You would only do this to try and shrink the end binary if dhcpcd + * was running on a low memory device */ + +#define ENABLE_ARP +#define ENABLE_NTP +#define ENABLE_NIS +#define ENABLE_INFO +/* Define this to enable some compatability with 1.x and 2.x info files */ +/* #define ENABLE_INFO_COMPAT */ + +/* IPV4LL, aka ZeroConf, aka APIPA, aka RFC 3927. + * Needs ARP. */ +#define ENABLE_IPV4LL + +/* We will auto create a DUID_LLT file if it doesn't exist. + * You can always create your own DUID file that just contains the + * hex string that represents the DUID. + * See RFC 3315 for details on this. */ +#define ENABLE_DUID + +/* resolvconf is framework for multiple interfaces to manage resolv.conf */ +#define ENABLE_RESOLVCONF + +/* Some systems do not have a working fork. + * The Makefile will attempt to work it out, but if it fails to feel free to + * define it here. */ +/* #define THERE_IS_NO_FORK */ + +/* Packname name and pathname definitions. */ + +#define PACKAGE "dhcpcd" + +#define ETCDIR "/etc" +#define RESOLVFILE ETCDIR "/resolv.conf" + +#define NISFILE ETCDIR "/yp.conf" + +#define NTPFILE ETCDIR "/ntp.conf" +#define NTPDRIFTFILE ETCDIR "/ntp.drift" +#define NTPLOGFILE "/var/log/ntp.log" + +#define OPENNTPFILE ETCDIR "/ntpd.conf" + +#define DEFAULT_SCRIPT ETCDIR "/" PACKAGE ".sh" + +#define STATEDIR "/var" +#define PIDFILE STATEDIR "/run/" PACKAGE "-%s.pid" + +#ifndef INFODIR +# define INFODIR "/var/lib/dhcpcd" +#endif +#define INFOFILE INFODIR "/" PACKAGE "-%s.info" +#define DUIDFILE INFODIR "/" PACKAGE ".duid" + +/* OPENRC is Open Run Control, forked from Gentoo's baselayout package + * BSDRC is BSD style Run Control + * SLACKRC is Slackware Run Control + * SERVICE is RedHat service command + * SYSV should cover everthing else */ +#ifdef ENABLE_OPENRC +# define SERVICE "OPENRC" +# define NISSERVICE ETCDIR "/init.d/ypbind" +# define NISRESTARTARGS "--nodeps", "--quiet", "conditionalrestart" +# define NTPSERVICE ETCDIR "/init.d/ntpd" +# define NTPRESTARTARGS "--nodeps", "--quiet", "conditionalrestart" +#endif +#if ENABLE_BSDRC +# define SERVICE "BSDRC" +# define NISSERVICE ETCDIR "/rc.d/ypbind" +# define NISRESTARTARGS "restart" +# define NTPSERVICE ETCDIR "/rc.d/ntpd" +# define NTPRESTARTARGS "restart" +#endif +#if ENABLE_SLACKRC +# define SERVICE "SLACKRC" +# define NISSERVICE ETCDIR "/rc.d/rc.ypbind" +# define NISRESTARTARGS "restart" +# define NTPSERVICE ETCDIR "/rc.d/rc.ntpd" +# define NTPRESTARTARGS "restart" +#endif +#if ENABLE_SERVICE +# define SERVICE "SERVICE" +# define NISSERVICE "service" +# define NISRESTARTARGS "ypbind", "restart" +# define NTPSERVICE "service" +# define NTPRESTARTARGS "ntpd", "restart" +#endif +#if ENABLE_SYSV +# define SERVICE "SYSV" +# define NISSERVICE ETCDIR "/init.d/ypbind" +# define NISRESTARTARGS "restart" +# define NTPSERVICE ETCDIR "/init.d/ntpd" +# define NTPRESTARTARGS "restart" +#endif + +#ifndef NISSERVICE +# undef ENABLE_NIS +#endif +#ifndef NTPSERVICE +# undef ENABLE_NTP +#endif + +#endif diff --git a/src/customdhcpcd/configure.c b/src/customdhcpcd/configure.c new file mode 100644 index 0000000..b69ccdc --- /dev/null +++ b/src/customdhcpcd/configure.c @@ -0,0 +1,814 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#ifdef __linux__ +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "configure.h" +#include "dhcp.h" +#ifdef ENABLE_INFO +# include "info.h" +#endif +#include "interface.h" +#include "dhcpcd.h" +#include "logger.h" +#include "signal.h" +#include "socket.h" + +#include "logwriter.h" + +static int file_in_path (const char *file) +{ + char *p = getenv ("PATH"); + char *path; + char *token; + struct stat s; + char mypath[PATH_MAX]; + int retval = -1; + + if (! p) { + errno = ENOENT; + return (-1); + } + + path = strdup (p); + p = path; + while ((token = strsep (&p, ":"))) { + snprintf (mypath, PATH_MAX, "%s/%s", token, file); + if (stat (mypath, &s) == 0) { + retval = 0; + break; + } + } + free (path); + return (retval); +} + +/* IMPORTANT: Ensure that the last parameter is NULL when calling */ +static int exec_cmd (const char *cmd, const char *args, ...) +{ + va_list va; + char **argv; + int n = 1; + int ret = 0; + pid_t pid; + sigset_t full; + sigset_t old; + + va_start (va, args); + while (va_arg (va, char *) != NULL) + n++; + va_end (va); + argv = xmalloc (sizeof (char *) * (n + 2)); + + va_start (va, args); + n = 2; + argv[0] = (char *) cmd; + argv[1] = (char *) args; + while ((argv[n] = va_arg (va, char *)) != NULL) + n++; + va_end (va); + + /* OK, we need to block signals */ + sigfillset (&full); + sigprocmask (SIG_SETMASK, &full, &old); + +#ifdef THERE_IS_NO_FORK + signal_reset (); + pid = vfork (); +#else + pid = fork(); +#endif + + switch (pid) { + case -1: + logger (LOG_ERR, "vfork: %s", strerror (errno)); + ret = -1; + break; + case 0: +#ifndef THERE_IS_NO_FORK + signal_reset (); +#endif + sigprocmask (SIG_SETMASK, &old, NULL); + if (execvp (cmd, argv) && errno != ENOENT) + logger (LOG_ERR, "error executing \"%s\": %s", + cmd, strerror (errno)); + _exit (111); + /* NOTREACHED */ + } + +#ifdef THERE_IS_NO_FORK + signal_setup (); +#endif + + /* Restore our signals */ + sigprocmask (SIG_SETMASK, &old, NULL); + + free (argv); + return (ret); +} + +static void exec_script (const char *script, const char *infofile, + const char *arg) +{ + struct stat buf; + + if (! script || ! infofile || ! arg) + return; + + if (stat (script, &buf) == -1) { + if (strcmp (script, DEFAULT_SCRIPT) != 0) + logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT)); + return; + } + +#ifdef ENABLE_INFO + logger (LOG_DEBUG, "exec \"%s\" \"%s\" \"%s\"", script, infofile, arg); + exec_cmd (script, infofile, arg, (char *) NULL); +#else + logger (LOG_DEBUG, "exec \"%s\" \"\" \"%s\"", script, arg); + exec_cmd (script, "", arg, (char *) NULL); +#endif +} + +static int make_resolv (const char *ifname, const dhcp_t *dhcp) +{ + FILE *f = NULL; + address_t *address; + +#ifdef ENABLE_RESOLVCONF + char *resolvconf = NULL; + + if (file_in_path ("resolvconf") == 0) { + size_t len = strlen ("resolvconf -a ") + strlen (ifname) + 1; + resolvconf = xmalloc (sizeof (char) * len); + snprintf (resolvconf, len, "resolvconf -a %s", ifname); + if ((f = popen (resolvconf , "w"))) + logger (LOG_DEBUG, + "sending DNS information to resolvconf"); + else if (errno == EEXIST) + logger (LOG_ERR, "popen: %s", strerror (errno)); + + if (ferror (f)) + logger (LOG_ERR, "ferror"); + free (resolvconf); + } +#endif + if (! f) { + logger (LOG_DEBUG, "writing "RESOLVFILE); + if (! (f = fopen(RESOLVFILE, "w"))) + logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno)); + } + + if (! f) + return (-1); + + fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); + if (dhcp->dnssearch) + fprintf (f, "search %s\n", dhcp->dnssearch); + else if (dhcp->dnsdomain) { + fprintf (f, "search %s\n", dhcp->dnsdomain); + } + + STAILQ_FOREACH (address, dhcp->dnsservers, entries) + fprintf (f, "nameserver %s\n", inet_ntoa (address->address)); + +#ifdef ENABLE_RESOLVCONF + if (resolvconf) + pclose (f); + else +#endif + fclose (f); + + /* Refresh the local resolver */ + res_init (); + return (0); +} + +static void restore_resolv (const char *ifname) +{ +#ifdef ENABLE_RESOLVCONF + if (file_in_path ("resolvconf") == 0) { + logger (LOG_DEBUG, "removing information from resolvconf"); + exec_cmd("resolvconf", "-d", ifname, (char *) NULL); + } +#endif +} + +static bool in_addresses (const struct address_head *addresses, + struct in_addr address) +{ + const address_t *addr; + + STAILQ_FOREACH (addr, addresses, entries) + if (addr->address.s_addr == address.s_addr) + return (true); + + return (false); +} + +static bool in_routes (const struct route_head *routes, route_t *route) +{ + const route_t *r; + + if (! routes) + return (false); + + STAILQ_FOREACH (r, routes, entries) + if (r->destination.s_addr == route->destination.s_addr && + r->netmask.s_addr == route->netmask.s_addr && + r->gateway.s_addr == route->gateway.s_addr) + return (true); + + return (false); +} + +#ifdef ENABLE_NTP +static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) +{ + FILE *f; + address_t *address; + char *a; + char *line; + int tomatch = 0; + char *token; + bool ntp = false; + + STAILQ_FOREACH (address, dhcp->ntpservers, entries) + tomatch++; + + /* Check that we really need to update the servers. + * We do this because ntp has to be restarted to + * work with a changed config. */ + if (! (f = fopen (file, "r"))) { + if (errno != ENOENT) { + logger (LOG_ERR, "fopen `%s': %s", + file, strerror (errno)); + return (-1); + } + } else { + while (tomatch != 0 && (line = get_line (f))) { + struct in_addr addr; + + a = line; + token = strsep (&a, " "); + if (! token || strcmp (token, "server") != 0) + goto next; + + if ((token = strsep (&a, " \n")) == NULL) + goto next; + + if (inet_aton (token, &addr) == 1 && + in_addresses (dhcp->ntpservers, addr)) + tomatch--; + +next: + free (line); + } + fclose (f); + + /* File has the same name servers that we do, + * so no need to restart ntp */ + if (tomatch == 0) { + logger (LOG_DEBUG, "%s already configured, skipping", + file); + return (0); + } + } + + logger (LOG_DEBUG, "writing %s", file); + if (! (f = fopen (file, "w"))) { + logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno)); + return (-1); + } + + fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); +#ifdef NTPFILE + if (strcmp (file, NTPFILE) == 0) { + ntp = true; + fprintf (f, "restrict default noquery notrust nomodify\n"); + fprintf (f, "restrict 127.0.0.1\n"); + } +#endif + + STAILQ_FOREACH (address, dhcp->ntpservers, entries) { + a = inet_ntoa (address->address); + if (ntp) + fprintf (f, "restrict %s nomodify notrap noquery\n", a); + fprintf (f, "server %s\n", a); + } + fclose (f); + + return (1); +} + +static int make_ntp (const char *ifname, const dhcp_t *dhcp) +{ + /* On some systems we have only have one ntp service, but we don't + * know which configuration file we're using. So we need to write + * to both and restart accordingly. */ + + bool restart_ntp = false; + bool restart_openntp = false; + int retval = 0; + +#ifdef NTPFILE + if (_make_ntp (NTPFILE, ifname, dhcp) > 0) + restart_ntp = true; +#endif + +#ifdef OPENNTPFILE + if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0) + restart_openntp = true; +#endif + +#ifdef NTPSERVICE + if (restart_ntp) { +#ifdef NTPCHECK + if (system (NTPCHECK) == 0) +#endif + retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, + (char *) NULL); + } +#endif + +#if defined (NTPSERVICE) && defined (OPENNTPSERVICE) + if (restart_openntp && + (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp)) + { +#ifdef OPENNTPCHECK + if (system (OPENNTPCHECK) == 0) +#endif + retval += exec_cmd (OPENNTPSERVICE, + OPENNTPRESTARTARGS, (char *) NULL); + } +#elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE) + if (restart_openntp) { +#ifdef OPENNTPCHECK + if (system (OPENNTPCHECK) == 0) +#endif + retval += exec_cmd (OPENNTPSERVICE, + OPENNTPRESTARTARGS, (char *) NULL); + } +#endif + + return (retval); +} +#endif + +#ifdef ENABLE_NIS +#define PREFIXSIZE 256 +static int make_nis (const char *ifname, const dhcp_t *dhcp) +{ + FILE *f; + address_t *address; + char *prefix; + + logger (LOG_DEBUG, "writing "NISFILE); + if (! (f = fopen(NISFILE, "w"))) { + logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno)); + return (-1); + } + + prefix = xmalloc (sizeof (char) * PREFIXSIZE); + *prefix = '\0'; + fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); + + if (dhcp->nisdomain) { + setdomainname (dhcp->nisdomain, (int) strlen (dhcp->nisdomain)); + + if (dhcp->nisservers) + snprintf (prefix, PREFIXSIZE, "domain %s server", + dhcp->nisdomain); + else + fprintf (f, "domain %s broadcast\n", dhcp->nisdomain); + } + else + snprintf (prefix, PREFIXSIZE, "%s", "ypserver"); + + NSTAILQ_FOREACH (address, dhcp->nisservers, entries) + fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address)); + + free (prefix); + fclose (f); + +#ifdef NISCHECK + if (system (NISCHECK) == 0) +#endif + exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL); + return (0); +} +#endif + +static char *lookuphostname (char *hostname, const dhcp_t *dhcp, + const options_t *options) +{ + union { + struct sockaddr sa; + struct sockaddr_in sin; + } su; + socklen_t salen; + char *addr; + struct addrinfo hints; + struct addrinfo *res = NULL; + int result; + char *p; + + logger (LOG_DEBUG, "Looking up hostname via DNS"); + addr = xmalloc (sizeof (char) * NI_MAXHOST); + salen = sizeof (su.sa); + memset (&su.sa, 0, salen); + su.sin.sin_family = AF_INET; + memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (su.sin.sin_addr)); + + if ((result = getnameinfo (&su.sa, salen, addr, NI_MAXHOST, + NULL, 0, NI_NAMEREQD)) != 0) { + logger (LOG_ERR, + "Failed to lookup hostname via DNS: %s", + gai_strerror (result)); + free (addr); + return (NULL); + } + + /* Check for a malicious PTR record */ + memset (&hints, 0, sizeof (hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + result = getaddrinfo (addr, "0", &hints, &res); + if (res) + freeaddrinfo (res); + if (result == 0) + logger (LOG_ERR, "malicious PTR record detected"); + if (result == 0 || ! *addr) { + free (addr); + return (NULL); + } + + p = strchr (addr, '.'); + if (p) { + switch (options->dohostname) { + case 1: /* -H */ + case 4: /* -HHHH */ + break; + case 2: /* -HH */ + case 5: /* -HHHHH */ + /* Strip out the domain if it matches */ + p++; + if (*p && dhcp->dnssearch) { + char *s = xstrdup (dhcp->dnssearch); + char *sp = s; + char *t; + + while ((t = strsep (&sp, " "))) + if (strcmp (t, p) == 0) { + *--p = '\0'; + break; + } + free (s); + } else if (dhcp->dnsdomain) { + if (strcmp (dhcp->dnsdomain, p) == 0) + *--p = '\0'; + } + break; + case 3: /* -HHH */ + case 6: /* -HHHHHH */ + /* Just strip the domain */ + *p = '\0'; + break; + default: /* Too many H! */ + break; + } + } + + strlcpy (hostname, addr, MAXHOSTNAMELEN); + free (addr); + return (hostname); +} + +int configure (const options_t *options, interface_t *iface, + const dhcp_t *dhcp, bool up) +{ + route_t *route = NULL; + struct route_head *new_routes = NULL; + route_t *new_route = NULL; + char *newhostname = NULL; + char *curhostname = NULL; + int remember; +#ifdef ENABLE_IPV4LL + bool haslinklocal = false; +#endif +#ifdef THERE_IS_NO_FORK + int skip = 0; + size_t skiplen; + char *skipp; +#endif + + if (! options || ! iface || ! dhcp) + return (-1); + + if (dhcp->address.s_addr == 0) + up = 0; + + logGatewayToFile(iface, dhcp); + + /* Remove old routes. + * Always do this as the interface may have >1 address not added by us + * so the routes we added may still exist. */ + NSTAILQ_FOREACH (route, iface->previous_routes, entries) + if ((route->destination.s_addr || options->dogateway) && + (! up || ! in_routes (dhcp->routes, route))) + del_route (iface->name, route->destination, + route->netmask, route->gateway, + options->metric); + /* If we aren't up, then reset the interface as much as we can */ + if (! up) { + if (iface->previous_routes) { + free_route (iface->previous_routes); + iface->previous_routes = NULL; + } + + /* Restore the original MTU value */ + if (iface->mtu && iface->previous_mtu != iface->mtu) { + set_mtu (iface->name, iface->mtu); + iface->previous_mtu = iface->mtu; + } + +#ifdef ENABLE_INFO + /* If we haven't created an info file, do so now */ + if (! dhcp->frominfo) + write_info (iface, dhcp, options, false); +#endif + + /* Only reset things if we had set them before */ + if (iface->previous_address.s_addr != 0) { + if (! options->keep_address) { + del_address (iface->name, + iface->previous_address, + iface->previous_netmask); + memset (&iface->previous_address, + 0, sizeof (iface->previous_address)); + memset (&iface->previous_netmask, + 0, sizeof (iface->previous_netmask)); + } + } + + restore_resolv (iface->name); + exec_script (options->script, iface->infofile, "down"); + + return (0); + } + + /* Set the MTU requested. + * If the DHCP server no longer sends one OR it's invalid then + * we restore the original MTU */ + if (options->domtu) { + unsigned short mtu = iface->mtu; + if (dhcp->mtu) + mtu = dhcp->mtu; + + if (mtu != iface->previous_mtu) { + if (set_mtu (iface->name, mtu) == 0) + iface->previous_mtu = mtu; + } + } + + /* This also changes netmask */ + if (! options->doinform || ! has_address (iface->name, dhcp->address)) + if (add_address (iface->name, dhcp->address, dhcp->netmask, + dhcp->broadcast) == -1 && errno != EEXIST) + return (false); + + /* Now delete the old address if different */ + if (iface->previous_address.s_addr != dhcp->address.s_addr && + iface->previous_address.s_addr != 0 && + ! options->keep_address) + del_address (iface->name, + iface->previous_address, iface->previous_netmask); + +#ifdef __linux__ + /* On linux, we need to change the subnet route to have our metric. */ + if (iface->previous_address.s_addr != dhcp->address.s_addr && + options->metric > 0 && + dhcp->netmask.s_addr != INADDR_BROADCAST) + { + struct in_addr td; + struct in_addr tg; + memset (&td, 0, sizeof (td)); + memset (&tg, 0, sizeof (tg)); + td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; + add_route (iface->name, td, dhcp->netmask, tg, options->metric); + del_route (iface->name, td, dhcp->netmask, tg, 0); + } +#endif + +#ifdef THERE_IS_NO_FORK + free (dhcpcd_skiproutes); + /* We can never have more than 255 routes. So we need space + * for 255 3 digit numbers and commas */ + skiplen = 255 * 4 + 1; + skipp = dhcpcd_skiproutes = xmalloc (sizeof (char) * skiplen); + *skipp = '\0'; +#endif + + /* Remember added routes */ + NSTAILQ_FOREACH (route, dhcp->routes, entries) { +#ifdef ENABLE_IPV4LL + /* Check if we have already got a link locale route dished + * out by the DHCP server */ + if (route->destination.s_addr == htonl (LINKLOCAL_ADDR) && + route->netmask.s_addr == htonl (LINKLOCAL_MASK)) + haslinklocal = true; +#endif + /* Don't set default routes if not asked to */ + if (route->destination.s_addr == 0 && + route->netmask.s_addr == 0 && + ! options->dogateway) + continue; + + remember = add_route (iface->name, route->destination, + route->netmask, route->gateway, + options->metric); + /* If we failed to add the route, we may have already added it + ourselves. If so, remember it again. */ + if (remember < 0 && in_routes (iface->previous_routes, route)) + remember = 1; + + if (remember >= 0) { + if (! new_routes) { + new_routes = xmalloc (sizeof (*new_routes)); + STAILQ_INIT (new_routes); + } + new_route = xmalloc (sizeof (route_t)); + memcpy (new_route, route, sizeof (*new_route)); + STAILQ_INSERT_TAIL (new_routes, new_route, entries); + } +#ifdef THERE_IS_NO_FORK + /* If we have daemonised yet we need to record which routes + * we failed to add so we can skip them */ + else if (! options->daemonised) { + /* We can never have more than 255 / 4 routes, + * so 3 chars is plently */ + if (*skipp) + *skipp++ = ','; + skipp += snprintf (skipp, + dhcpcd_skiproutes + skiplen - skipp, + "%d", skip); + } + skip++; +#endif + } + +#ifdef THERE_IS_NO_FORK + if (*dhcpcd_skiproutes) + *skipp = '\0'; + else { + free (dhcpcd_skiproutes); + dhcpcd_skiproutes = NULL; + } +#endif + +#ifdef ENABLE_IPV4LL + /* Ensure we always add the link local route if we got a private + * address and isn't link local itself */ + if (options->doipv4ll && + ! haslinklocal && + IN_PRIVATE (ntohl (dhcp->address.s_addr))) + { + struct in_addr dest; + struct in_addr mask; + struct in_addr gate; + + dest.s_addr = htonl (LINKLOCAL_ADDR); + mask.s_addr = htonl (LINKLOCAL_MASK); + gate.s_addr = 0; + remember = add_route (iface->name, dest, mask, gate, + options->metric); + + if (remember >= 0) { + if (! new_routes) { + new_routes = xmalloc (sizeof (*new_routes)); + STAILQ_INIT (new_routes); + } + new_route = xmalloc (sizeof (*new_route)); + new_route->destination.s_addr = dest.s_addr; + new_route->netmask.s_addr = mask.s_addr; + new_route->gateway.s_addr = gate.s_addr; + STAILQ_INSERT_TAIL (new_routes, new_route, entries); + } + } +#endif + + if (iface->previous_routes) + free_route (iface->previous_routes); + iface->previous_routes = new_routes; + + logToQt(LOG_INFO, DHCPCD_WRITE, ""); + if (options->dodns && dhcp->dnsservers) + make_resolv(iface->name, dhcp); + else + logger (LOG_DEBUG, "no dns information to write"); + +#ifdef ENABLE_NTP + if (options->dontp && dhcp->ntpservers) + make_ntp(iface->name, dhcp); +#endif + +#ifdef ENABLE_NIS + if (options->donis && (dhcp->nisservers || dhcp->nisdomain)) + make_nis(iface->name, dhcp); +#endif + + curhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); + *curhostname = '\0'; + + gethostname (curhostname, MAXHOSTNAMELEN); + if (options->dohostname || + strlen (curhostname) == 0 || + strcmp (curhostname, "(none)") == 0 || + strcmp (curhostname, "localhost") == 0) + { + newhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); + + if (dhcp->hostname) + strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN); + else + *newhostname = '\0'; + + /* Now we have made a resolv.conf we can obtain a hostname + * if we need it */ + if (! *newhostname || options->dohostname > 3) + lookuphostname (newhostname, dhcp, options); + + if (*newhostname) { + logger (LOG_INFO, "setting hostname to `%s'", + newhostname); + sethostname (newhostname, (int) strlen (newhostname)); + } + + free (newhostname); + } + + free (curhostname); + +#ifdef ENABLE_INFO + if (! dhcp->frominfo) + write_info (iface, dhcp, options, true); +#endif + + if (iface->previous_address.s_addr != dhcp->address.s_addr || + iface->previous_netmask.s_addr != dhcp->netmask.s_addr) + { + memcpy (&iface->previous_address, + &dhcp->address, sizeof (iface->previous_address)); + memcpy (&iface->previous_netmask, + &dhcp->netmask, sizeof (iface->previous_netmask)); + exec_script (options->script, iface->infofile, "new"); + } else + exec_script (options->script, iface->infofile, "up"); + + return (0); +} diff --git a/src/customdhcpcd/configure.h b/src/customdhcpcd/configure.h new file mode 100644 index 0000000..3166947 --- /dev/null +++ b/src/customdhcpcd/configure.h @@ -0,0 +1,38 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef DHCPCONFIG_H +#define DHCPCONFIG_H + +#include "dhcpcd.h" +#include "interface.h" +#include "dhcp.h" + +int configure (const options_t *options, interface_t *iface, + const dhcp_t *dhcp, bool up); + +#endif diff --git a/src/customdhcpcd/dhcp.c b/src/customdhcpcd/dhcp.c new file mode 100644 index 0000000..f625e8f --- /dev/null +++ b/src/customdhcpcd/dhcp.c @@ -0,0 +1,933 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "common.h" +#include "dhcpcd.h" +#include "dhcp.h" +#include "interface.h" +#include "logger.h" +#include "socket.h" + +#ifndef STAILQ_CONCAT +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) +#endif + +typedef struct message { + int value; + const char *name; +} dhcp_message_t; + +static dhcp_message_t dhcp_messages[] = { + { DHCP_DISCOVER, "DHCP_DISCOVER" }, + { DHCP_OFFER, "DHCP_OFFER" }, + { DHCP_REQUEST, "DHCP_REQUEST" }, + { DHCP_DECLINE, "DHCP_DECLINE" }, + { DHCP_ACK, "DHCP_ACK" }, + { DHCP_NAK, "DHCP_NAK" }, + { DHCP_RELEASE, "DHCP_RELEASE" }, + { DHCP_INFORM, "DHCP_INFORM" }, + { -1, NULL } +}; + +static const char *dhcp_message (int type) +{ + dhcp_message_t *d; + for (d = dhcp_messages; d->name; d++) + if (d->value == type) + return (d->name); + + return (NULL); +} + +ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp, + uint32_t xid, char type, const options_t *options) +{ + struct udp_dhcp_packet *packet; + dhcpmessage_t *message; + unsigned char *m; + unsigned char *p; + unsigned char *n_params = NULL; + size_t l; + struct in_addr from; + struct in_addr to; + time_t up = uptime() - iface->start_uptime; + uint32_t ul; + uint16_t sz; + size_t message_length; + ssize_t retval; + + if (!iface || !options || !dhcp) + return -1; + + memset (&from, 0, sizeof (from)); + memset (&to, 0, sizeof (to)); + + if (type == DHCP_RELEASE) + to.s_addr = dhcp->serveraddress.s_addr; + + message = xzalloc (sizeof (*message)); + m = (unsigned char *) message; + p = (unsigned char *) &message->options; + + if ((type == DHCP_INFORM || + type == DHCP_RELEASE || + type == DHCP_REQUEST) && + ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) + { + message->ciaddr = iface->previous_address.s_addr; + from.s_addr = iface->previous_address.s_addr; + + /* Just incase we haven't actually configured the address yet */ + if (type == DHCP_INFORM && iface->previous_address.s_addr == 0) + message->ciaddr = dhcp->address.s_addr; + + /* Zero the address if we're currently on a different subnet */ + if (type == DHCP_REQUEST && + iface->previous_netmask.s_addr != dhcp->netmask.s_addr) + message->ciaddr = from.s_addr = 0; + + if (from.s_addr != 0) + to.s_addr = dhcp->serveraddress.s_addr; + } + + message->op = DHCP_BOOTREQUEST; + message->hwtype = iface->family; + switch (iface->family) { + case ARPHRD_ETHER: + case ARPHRD_IEEE802: + message->hwlen = ETHER_ADDR_LEN; + memcpy (&message->chaddr, &iface->hwaddr, + ETHER_ADDR_LEN); + break; + case ARPHRD_IEEE1394: + case ARPHRD_INFINIBAND: + message->hwlen = 0; + if (message->ciaddr == 0) + message->flags = htons (BROADCAST_FLAG); + break; + default: + logger (LOG_ERR, "dhcp: unknown hardware type %d", + iface->family); + } + + if (up < 0 || up > (time_t) UINT16_MAX) + message->secs = htons ((uint16_t) UINT16_MAX); + else + message->secs = htons (up); + message->xid = xid; + message->cookie = htonl (MAGIC_COOKIE); + + *p++ = DHCP_MESSAGETYPE; + *p++ = 1; + *p++ = type; + + if (type == DHCP_REQUEST) { + *p++ = DHCP_MAXMESSAGESIZE; + *p++ = 2; + sz = get_mtu (iface->name); + if (sz < MTU_MIN) { + if (set_mtu (iface->name, MTU_MIN) == 0) + sz = MTU_MIN; + } + sz = htons (sz); + memcpy (p, &sz, 2); + p += 2; + } + + *p++ = DHCP_CLIENTID; + *p++ = iface->clientid_len; + memcpy (p, iface->clientid, iface->clientid_len); + p+= iface->clientid_len; + + if (type != DHCP_DECLINE && type != DHCP_RELEASE) { + if (options->userclass_len > 0) { + *p++ = DHCP_USERCLASS; + *p++ = options->userclass_len; + memcpy (p, &options->userclass, options->userclass_len); + p += options->userclass_len; + } + + if (*options->classid > 0) { + *p++ = DHCP_CLASSID; + *p++ = l = strlen (options->classid); + memcpy (p, options->classid, l); + p += l; + } + } + + if (type == DHCP_DISCOVER || type == DHCP_REQUEST) { +#define PUTADDR(_type, _val) { \ + *p++ = _type; \ + *p++ = 4; \ + memcpy (p, &_val.s_addr, 4); \ + p += 4; \ +} + if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) + logger (LOG_ERR, + "cannot request a link local address"); + else { + if (dhcp->address.s_addr && + dhcp->address.s_addr != + iface->previous_address.s_addr) + { + PUTADDR (DHCP_ADDRESS, dhcp->address); + if (dhcp->serveraddress.s_addr) + PUTADDR (DHCP_SERVERIDENTIFIER, + dhcp->serveraddress); + } + } +#undef PUTADDR + + if (options->leasetime != 0) { + *p++ = DHCP_LEASETIME; + *p++ = 4; + ul = htonl (options->leasetime); + memcpy (p, &ul, 4); + p += 4; + } + } + + if (type == DHCP_DISCOVER || + type == DHCP_INFORM || + type == DHCP_REQUEST) + { + if (options->hostname[0]) { + if (options->fqdn == FQDN_DISABLE) { + *p++ = DHCP_HOSTNAME; + *p++ = l = strlen (options->hostname); + memcpy (p, options->hostname, l); + p += l; + } else { + /* Draft IETF DHC-FQDN option (81) */ + *p++ = DHCP_FQDN; + *p++ = (l = strlen (options->hostname)) + 3; + /* Flags: 0000NEOS + * S: 1 => Client requests Server to update + * a RR in DNS as well as PTR + * O: 1 => Server indicates to client that + * DNS has been updated + * E: 1 => Name data is DNS format + * N: 1 => Client requests Server to not + * update DNS + */ + *p++ = options->fqdn & 0x9; + *p++ = 0; /* from server for PTR RR */ + *p++ = 0; /* from server for A RR if S=1 */ + memcpy (p, options->hostname, l); + p += l; + } + } + + *p++ = DHCP_PARAMETERREQUESTLIST; + n_params = p; + *p++ = 0; + /* Only request DNSSERVER in discover to keep the packets small. + * RFC2131 Section 3.5 states that the REQUEST must include the + * list from the DISCOVER message, so I think this is ok. */ + + if (type == DHCP_DISCOVER && ! options->test) + *p++ = DHCP_DNSSERVER; + else { + if (type != DHCP_INFORM) { + *p++ = DHCP_RENEWALTIME; + *p++ = DHCP_REBINDTIME; + } + *p++ = DHCP_NETMASK; + *p++ = DHCP_BROADCAST; + + /* -S means request CSR and MSCSR + * -SS means only request MSCSR incase DHCP message + * is too big */ + if (options->domscsr < 2) + *p++ = DHCP_CSR; + if (options->domscsr > 0) + *p++ = DHCP_MSCSR; + /* RFC 3442 states classless static routes should be + * before routers and static routes as classless static + * routes override them both */ + *p++ = DHCP_STATICROUTE; + *p++ = DHCP_ROUTERS; + *p++ = DHCP_HOSTNAME; + *p++ = DHCP_DNSSEARCH; + *p++ = DHCP_DNSDOMAIN; + *p++ = DHCP_DNSSERVER; +#ifdef ENABLE_NIS + *p++ = DHCP_NISDOMAIN; + *p++ = DHCP_NISSERVER; +#endif +#ifdef ENABLE_NTP + *p++ = DHCP_NTPSERVER; +#endif + *p++ = DHCP_MTU; +#ifdef ENABLE_INFO + *p++ = DHCP_ROOTPATH; + *p++ = DHCP_SIPSERVER; +#endif + } + + *n_params = p - n_params - 1; + } + *p++ = DHCP_END; + +#ifdef BOOTP_MESSAGE_LENTH_MIN + /* Some crappy DHCP servers think they have to obey the BOOTP minimum + * message length. + * They are wrong, but we should still cater for them. */ + while (p - m < BOOTP_MESSAGE_LENTH_MIN) + *p++ = DHCP_PAD; +#endif + + message_length = p - m; + + packet = xzalloc (sizeof (*packet)); + make_dhcp_packet (packet, (unsigned char *) message, message_length, + from, to); + free (message); + + logger (LOG_DEBUG, "sending %s with xid 0x%x", + dhcp_message (type), xid); + retval = send_packet (iface, ETHERTYPE_IP, (unsigned char *) packet, + message_length + + sizeof (packet->ip) + sizeof (packet->udp)); + free (packet); + return (retval); +} + +/* Decode an RFC3397 DNS search order option into a space + * seperated string. Returns length of string (including + * terminating zero) or zero on error. out may be NULL + * to just determine output length. */ +static unsigned int decode_search (const unsigned char *p, int len, char *out) +{ + const unsigned char *r, *q = p; + unsigned int count = 0, l, hops; + + while (q - p < len) { + r = NULL; + hops = 0; + while ((l = *q++)) { + unsigned int label_type = l & 0xc0; + if (label_type == 0x80 || label_type == 0x40) + return 0; + else if (label_type == 0xc0) { /* pointer */ + l = (l & 0x3f) << 8; + l |= *q++; + + /* save source of first jump. */ + if (!r) + r = q; + + hops++; + if (hops > 255) + return 0; + + q = p + l; + if (q - p >= len) + return 0; + } else { + /* straightforward name segment, add with '.' */ + count += l + 1; + if (out) { + memcpy (out, q, l); + out += l; + *out++ = '.'; + } + q += l; + } + } + + /* change last dot to space */ + if (out) + *(out - 1) = ' '; + + if (r) + q = r; + } + + /* change last space to zero terminator */ + if (out) + *(out - 1) = 0; + + return count; +} + +/* Add our classless static routes to the routes variable + * and return the last route set */ +static struct route_head *decode_CSR (const unsigned char *p, int len) +{ + const unsigned char *q = p; + unsigned int cidr; + unsigned int ocets; + struct route_head *routes = NULL; + route_t *route; + + /* Minimum is 5 -first is CIDR and a router length of 4 */ + if (len < 5) + return NULL; + + while (q - p < len) { + if (! routes) { + routes = xmalloc (sizeof (*routes)); + STAILQ_INIT (routes); + } + + route = xzalloc (sizeof (*route)); + + cidr = *q++; + if (cidr > 32) { + logger (LOG_ERR, + "invalid CIDR of %d in classless static route", + cidr); + free_route (routes); + return (NULL); + } + ocets = (cidr + 7) / 8; + + if (ocets > 0) { + memcpy (&route->destination.s_addr, q, (size_t) ocets); + q += ocets; + } + + /* Now enter the netmask */ + if (ocets > 0) { + memset (&route->netmask.s_addr, 255, (size_t) ocets - 1); + memset ((unsigned char *) &route->netmask.s_addr + + (ocets - 1), + (256 - (1 << (32 - cidr) % 8)), 1); + } + + /* Finally, snag the router */ + memcpy (&route->gateway.s_addr, q, 4); + q += 4; + + STAILQ_INSERT_TAIL (routes, route, entries); + } + + return (routes); +} + +void free_dhcp (dhcp_t *dhcp) +{ + if (! dhcp) + return; + + free_route (dhcp->routes); + free (dhcp->hostname); + free_address (dhcp->dnsservers); + free (dhcp->dnsdomain); + free (dhcp->dnssearch); + free_address (dhcp->ntpservers); + free (dhcp->nisdomain); + free_address (dhcp->nisservers); + free (dhcp->rootpath); + free (dhcp->sipservers); + if (dhcp->fqdn) { + free (dhcp->fqdn->name); + free (dhcp->fqdn); + } +} + + +static bool dhcp_add_address (struct address_head **addresses, + const unsigned char *data, + int length) +{ + int i; + address_t *address; + + for (i = 0; i < length; i += 4) { + /* Sanity check */ + if (i + 4 > length) { + logger (LOG_ERR, "invalid address length"); + return (false); + } + + if (*addresses == NULL) { + *addresses = xmalloc (sizeof (**addresses)); + STAILQ_INIT (*addresses); + } + address = xzalloc (sizeof (*address)); + memcpy (&address->address.s_addr, data + i, 4); + STAILQ_INSERT_TAIL (*addresses, address, entries); + } + + return (true); +} + +#ifdef ENABLE_INFO +static char *decode_sipservers (const unsigned char *data, int length) +{ + char *sip = NULL; + char *p; + const char encoding = *data++; + struct in_addr addr; + size_t len; + + length--; + + switch (encoding) { + case 0: + if ((len = decode_search (data, length, NULL)) > 0) { + sip = xmalloc (len); + decode_search (data, length, sip); + } + break; + + case 1: + if (length == 0 || length % 4 != 0) { + logger (LOG_ERR, + "invalid length %d for option 120", + length + 1); + break; + } + len = ((length / 4) * (4 * 4)) + 1; + sip = p = xmalloc (len); + while (length != 0) { + memcpy (&addr.s_addr, data, 4); + data += 4; + p += snprintf (p, len - (p - sip), + "%s ", inet_ntoa (addr)); + length -= 4; + } + *--p = '\0'; + break; + + default: + logger (LOG_ERR, "unknown sip encoding %d", encoding); + break; + } + + return (sip); +} +#endif + +/* This calculates the netmask that we should use for static routes. + * This IS different from the calculation used to calculate the netmask + * for an interface address. */ +static uint32_t route_netmask (uint32_t ip_in) +{ + /* used to be unsigned long - check if error */ + uint32_t p = ntohl (ip_in); + uint32_t t; + + if (IN_CLASSA (p)) + t = ~IN_CLASSA_NET; + else { + if (IN_CLASSB (p)) + t = ~IN_CLASSB_NET; + else { + if (IN_CLASSC (p)) + t = ~IN_CLASSC_NET; + else + t = 0; + } + } + + while (t & p) + t >>= 1; + + return (htonl (~t)); +} + +static struct route_head *decode_routes (const unsigned char *data, int length) +{ + int i; + struct route_head *head = NULL; + route_t *route; + + for (i = 0; i < length; i += 8) { + if (! head) { + head = xmalloc (sizeof (*head)); + STAILQ_INIT (head); + } + route = xzalloc (sizeof (*route)); + memcpy (&route->destination.s_addr, data + i, 4); + memcpy (&route->gateway.s_addr, data + i + 4, 4); + route->netmask.s_addr = + route_netmask (route->destination.s_addr); + STAILQ_INSERT_TAIL (head, route, entries); + } + + return (head); +} + +static struct route_head *decode_routers (const unsigned char *data, int length) +{ + int i; + struct route_head *head = NULL; + route_t *route = NULL; + + for (i = 0; i < length; i += 4) { + if (! head) { + head = xmalloc (sizeof (*head)); + STAILQ_INIT (head); + } + route = xzalloc (sizeof (*route)); + memcpy (&route->gateway.s_addr, data + i, 4); + STAILQ_INSERT_TAIL (head, route, entries); + } + + return (head); +} + +int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message) +{ + const unsigned char *p = message->options; + const unsigned char *end = p; /* Add size later for gcc-3 issue */ + unsigned char option; + unsigned char length; + unsigned int len = 0; + int retval = -1; + struct timeval tv; + struct route_head *routers = NULL; + struct route_head *routes = NULL; + struct route_head *csr = NULL; + struct route_head *mscsr = NULL; + bool in_overload = false; + bool parse_sname = false; + bool parse_file = false; + + end += sizeof (message->options); + + if (gettimeofday (&tv, NULL) == -1) { + logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); + return (-1); + } + + dhcp->address.s_addr = message->yiaddr; + dhcp->leasedfrom = tv.tv_sec; + dhcp->frominfo = false; + dhcp->address.s_addr = message->yiaddr; + strlcpy (dhcp->servername, (char *) message->servername, + sizeof (dhcp->servername)); + +#define LEN_ERR \ + { \ + logger (LOG_ERR, "invalid length %d for option %d", \ + length, option); \ + p += length; \ + continue; \ + } + +parse_start: + while (p < end) { + option = *p++; + if (! option) + continue; + + if (option == DHCP_END) + goto eexit; + + length = *p++; + + if (option != DHCP_PAD && length == 0) { + logger (LOG_ERR, "option %d has zero length", option); + retval = -1; + goto eexit; + } + + if (p + length >= end) { + logger (LOG_ERR, "dhcp option exceeds message length"); + retval = -1; + goto eexit; + } + + switch (option) { + case DHCP_MESSAGETYPE: + retval = (int) *p; + p += length; + continue; + + default: + if (length == 0) { + logger (LOG_DEBUG, + "option %d has zero length, skipping", + option); + continue; + } + } + +#define LENGTH(_length) \ + if (length != _length) \ + LEN_ERR; +#define MIN_LENGTH(_length) \ + if (length < _length) \ + LEN_ERR; +#define MULT_LENGTH(_mult) \ + if (length % _mult != 0) \ + LEN_ERR; +#define GET_UINT8(_val) \ + LENGTH (sizeof (uint8_t)); \ + memcpy (&_val, p, sizeof (uint8_t)); +#define GET_UINT16(_val) \ + LENGTH (sizeof (uint16_t)); \ + memcpy (&_val, p, sizeof (uint16_t)); +#define GET_UINT32(_val) \ + LENGTH (sizeof (uint32_t)); \ + memcpy (&_val, p, sizeof (uint32_t)); +#define GET_UINT16_H(_val) \ + GET_UINT16 (_val); \ + _val = ntohs (_val); +#define GET_UINT32_H(_val) \ + GET_UINT32 (_val); \ + _val = ntohl (_val); + + switch (option) { + case DHCP_ADDRESS: + GET_UINT32 (dhcp->address.s_addr); + break; + case DHCP_NETMASK: + GET_UINT32 (dhcp->netmask.s_addr); + break; + case DHCP_BROADCAST: + GET_UINT32 (dhcp->broadcast.s_addr); + break; + case DHCP_SERVERIDENTIFIER: + GET_UINT32 (dhcp->serveraddress.s_addr); + break; + case DHCP_LEASETIME: + GET_UINT32_H (dhcp->leasetime); + break; + case DHCP_RENEWALTIME: + GET_UINT32_H (dhcp->renewaltime); + break; + case DHCP_REBINDTIME: + GET_UINT32_H (dhcp->rebindtime); + break; + case DHCP_MTU: + GET_UINT16_H (dhcp->mtu); + /* Minimum legal mtu is 68 accoridng to + * RFC 2132. In practise it's 576 which is the + * minimum maximum message size. */ + if (dhcp->mtu < MTU_MIN) { + logger (LOG_DEBUG, + "MTU %d is too low, minimum is %d; ignoring", + dhcp->mtu, MTU_MIN); + dhcp->mtu = 0; + } + break; + +#undef GET_UINT32_H +#undef GET_UINT32 +#undef GET_UINT16_H +#undef GET_UINT16 +#undef GET_UINT8 + +#define GETSTR(_var) { \ + MIN_LENGTH (sizeof (char)); \ + if (_var) free (_var); \ + _var = xmalloc ((size_t) length + 1); \ + memcpy (_var, p, (size_t) length); \ + memset (_var + length, 0, 1); \ +} + case DHCP_HOSTNAME: + GETSTR (dhcp->hostname); + break; + case DHCP_DNSDOMAIN: + GETSTR (dhcp->dnsdomain); + break; + case DHCP_MESSAGE: + GETSTR (dhcp->message); + break; +#ifdef ENABLE_INFO + case DHCP_ROOTPATH: + GETSTR (dhcp->rootpath); + break; +#endif +#ifdef ENABLE_NIS + case DHCP_NISDOMAIN: + GETSTR (dhcp->nisdomain); + break; +#endif +#undef GETSTR + +#define GETADDR(_var) \ + MULT_LENGTH (4); \ + if (! dhcp_add_address (&_var, p, length)) \ + { \ + retval = -1; \ + goto eexit; \ + } + case DHCP_DNSSERVER: + GETADDR (dhcp->dnsservers); + break; +#ifdef ENABLE_NTP + case DHCP_NTPSERVER: + GETADDR (dhcp->ntpservers); + break; +#endif +#ifdef ENABLE_NIS + case DHCP_NISSERVER: + GETADDR (dhcp->nisservers); + break; +#endif +#undef GETADDR + + case DHCP_DNSSEARCH: + MIN_LENGTH (1); + free (dhcp->dnssearch); + len = decode_search (p, length, NULL); + if (len > 0) { + dhcp->dnssearch = xmalloc (len); + decode_search (p, length, + dhcp->dnssearch); + } + break; + + case DHCP_CSR: + MIN_LENGTH (5); + free_route (csr); + csr = decode_CSR (p, length); + break; + + case DHCP_MSCSR: + MIN_LENGTH (5); + free_route (mscsr); + mscsr = decode_CSR (p, length); + break; + +#ifdef ENABLE_INFO + case DHCP_SIPSERVER: + free (dhcp->sipservers); + dhcp->sipservers = decode_sipservers (p,length); + break; +#endif + + case DHCP_STATICROUTE: + MULT_LENGTH (8); + free_route (routes); + routes = decode_routes (p, length); + break; + + case DHCP_ROUTERS: + MULT_LENGTH (4); + free_route (routers); + routers = decode_routers (p, length); + break; + + case DHCP_OPTIONSOVERLOADED: + LENGTH (1); + /* The overloaded option in an overloaded option + * should be ignored, overwise we may get an + * infinite loop */ + if (! in_overload) { + if (*p & 1) + parse_file = true; + if (*p & 2) + parse_sname = true; + } + break; + + case DHCP_FQDN: + /* We ignore replies about FQDN */ + break; + +#undef LENGTH +#undef MIN_LENGTH +#undef MULT_LENGTH + + default: + logger (LOG_DEBUG, + "no facility to parse DHCP code %u", + option); + break; + } + + p += length; + } + +eexit: + /* We may have options overloaded, so go back and grab them */ + if (parse_file) { + parse_file = false; + p = message->bootfile; + end = p + sizeof (message->bootfile); + in_overload = true; + goto parse_start; + } else if (parse_sname) { + parse_sname = false; + p = message->servername; + end = p + sizeof (message->servername); + memset (dhcp->servername, 0, sizeof (dhcp->servername)); + in_overload = true; + goto parse_start; + } + + /* Fill in any missing fields */ + if (! dhcp->netmask.s_addr) + dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); + if (! dhcp->broadcast.s_addr) + dhcp->broadcast.s_addr = dhcp->address.s_addr | + ~dhcp->netmask.s_addr; + + /* If we have classess static routes then we discard + * static routes and routers according to RFC 3442 */ + if (csr) { + dhcp->routes = csr; + free_route (mscsr); + free_route (routers); + free_route (routes); + } else if (mscsr) { + dhcp->routes = mscsr; + free_route (routers); + free_route (routes); + } else { + /* Ensure that we apply static routes before routers */ + if (! routes) + routes = routers; + else if (routers) + STAILQ_CONCAT (routes, routers); + dhcp->routes = routes; + } + + return (retval); +} diff --git a/src/customdhcpcd/dhcp.h b/src/customdhcpcd/dhcp.h new file mode 100644 index 0000000..ef97b75 --- /dev/null +++ b/src/customdhcpcd/dhcp.h @@ -0,0 +1,215 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef DHCP_H +#define DHCP_H + +#include +#include +#include +#include +#include + +#include "dhcpcd.h" +#include "interface.h" + +/* Max MTU - defines dhcp option length */ +#define MTU_MAX 1500 +#define MTU_MIN 576 + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 +#define DHCP_CLIENT_PORT 68 + +#define MAGIC_COOKIE 0x63825363 +#define BROADCAST_FLAG 0x8000 + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +/* DHCP options */ +enum DHCP_OPTIONS +{ + DHCP_PAD = 0, + DHCP_NETMASK = 1, + DHCP_TIMEROFFSET = 2, + DHCP_ROUTERS = 3, + DHCP_TIMESERVER = 4, + DHCP_NAMESERVER = 5, + DHCP_DNSSERVER = 6, + DHCP_LOGSERVER = 7, + DHCP_COOKIESERVER = 8, + DHCP_HOSTNAME = 12, + DHCP_DNSDOMAIN = 15, + DHCP_ROOTPATH = 17, + DHCP_DEFAULTIPTTL = 23, + DHCP_MTU = 26, + DHCP_BROADCAST = 28, + DHCP_MASKDISCOVERY = 29, + DHCP_ROUTERDISCOVERY = 31, + DHCP_STATICROUTE = 33, + DHCP_NISDOMAIN = 40, + DHCP_NISSERVER = 41, + DHCP_NTPSERVER = 42, + DHCP_ADDRESS = 50, + DHCP_LEASETIME = 51, + DHCP_OPTIONSOVERLOADED = 52, + DHCP_MESSAGETYPE = 53, + DHCP_SERVERIDENTIFIER = 54, + DHCP_PARAMETERREQUESTLIST = 55, + DHCP_MESSAGE = 56, + DHCP_MAXMESSAGESIZE = 57, + DHCP_RENEWALTIME = 58, + DHCP_REBINDTIME = 59, + DHCP_CLASSID = 60, + DHCP_CLIENTID = 61, + DHCP_USERCLASS = 77, /* RFC 3004 */ + DHCP_FQDN = 81, + DHCP_DNSSEARCH = 119, /* RFC 3397 */ + DHCP_SIPSERVER = 120, /* RFC 3361 */ + DHCP_CSR = 121, /* RFC 3442 */ + DHCP_MSCSR = 249, /* MS code for RFC 3442 */ + DHCP_END = 255 +}; + +/* SetFQDNHostName values - lsnybble used in flags + * byte (see buildmsg.c), hsnybble to create order + * and to allow 0x00 to mean disable + */ +enum FQQN { + FQDN_DISABLE = 0x00, + FQDN_NONE = 0x18, + FQDN_PTR = 0x20, + FQDN_BOTH = 0x31 +}; + +typedef struct fqdn_t +{ + uint8_t flags; + uint8_t r1; + uint8_t r2; + char *name; +} fqdn_t; + +typedef struct dhcp_t +{ + char version[11]; + + struct in_addr serveraddress; + char serverhw[IF_NAMESIZE]; + char servername[64]; + + struct in_addr address; + struct in_addr netmask; + struct in_addr broadcast; + unsigned short mtu; + + uint32_t leasedfrom; + uint32_t leasetime; + uint32_t renewaltime; + uint32_t rebindtime; + + struct route_head *routes; + + char *hostname; + fqdn_t *fqdn; + + struct address_head *dnsservers; + char *dnsdomain; + char *dnssearch; + + struct address_head *ntpservers; + + struct address_head *nisservers; + char *nisdomain; + + char *sipservers; + + char *message; + char *rootpath; + + bool frominfo; +} dhcp_t; + +/* Sizes for DHCP options */ +#define DHCP_CHADDR_LEN 16 +#define SERVERNAME_LEN 64 +#define BOOTFILE_LEN 128 +#define DHCP_UDP_LEN (20 + 8) +#define DHCP_BASE_LEN (4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4) +#define DHCP_RESERVE_LEN (4 + 4 + 4 + 4 + 2) +#define DHCP_FIXED_LEN (DHCP_BASE_LEN + DHCP_CHADDR_LEN + \ + + SERVERNAME_LEN + BOOTFILE_LEN) +#define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \ + - DHCP_RESERVE_LEN) + +/* Some crappy DHCP servers require the BOOTP minimum length */ +#define BOOTP_MESSAGE_LENTH_MIN 300 + +typedef struct dhcpmessage_t +{ + unsigned char op; /* message type */ + unsigned char hwtype; /* hardware address type */ + unsigned char hwlen; /* hardware address length */ + unsigned char hwopcount; /* should be zero in client message */ + uint32_t xid; /* transaction id */ + uint16_t secs; /* elapsed time in sec. from boot */ + uint16_t flags; + uint32_t ciaddr; /* (previously allocated) client IP */ + uint32_t yiaddr; /* 'your' client IP address */ + uint32_t siaddr; /* should be zero in client's messages */ + uint32_t giaddr; /* should be zero in client's messages */ + unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ + unsigned char servername[SERVERNAME_LEN]; /* server host name */ + unsigned char bootfile[BOOTFILE_LEN]; /* boot file name */ + uint32_t cookie; + unsigned char options[DHCP_OPTION_LEN]; /* message options - cookie */ +} dhcpmessage_t; + +struct udp_dhcp_packet +{ + struct ip ip; + struct udphdr udp; + dhcpmessage_t dhcp; +}; + +ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp, + uint32_t xid, char type, const options_t *options); +void free_dhcp (dhcp_t *dhcp); +int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message); +#endif diff --git a/src/customdhcpcd/dhcpcd.c b/src/customdhcpcd/dhcpcd.c new file mode 100644 index 0000000..d0ad5e7 --- /dev/null +++ b/src/customdhcpcd/dhcpcd.c @@ -0,0 +1,671 @@ + /* dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +const char copyright[] = "Copyright (c) 2006-2008 Roy Marples"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "client.h" +#include "dhcpcd.h" +#include "dhcp.h" +#include "interface.h" +#include "logger.h" +#include "socket.h" +#include "version.h" + +#include "logwriter.h" + +static int doversion = 0; +static int dohelp = 0; +#define EXTRA_OPTS +static const struct option longopts[] = { + {"arp", no_argument, NULL, 'a'}, + {"script", required_argument, NULL, 'c'}, + {"debug", no_argument, NULL, 'd'}, + {"hostname", optional_argument, NULL, 'h'}, + {"classid", optional_argument, NULL, 'i'}, + {"release", no_argument, NULL, 'k'}, + {"leasetime", required_argument, NULL, 'l'}, + {"metric", required_argument, NULL, 'm'}, + {"renew", no_argument, NULL, 'n'}, + {"persistent", no_argument, NULL, 'p'}, + {"qtsocketaddress", required_argument, NULL, 'q'}, + {"inform", optional_argument, NULL, 's'}, + {"request", optional_argument, NULL, 'r'}, + {"timeout", required_argument, NULL, 't'}, + {"userclass", required_argument, NULL, 'u'}, + {"exit", no_argument, NULL, 'x'}, + {"lastlease", no_argument, NULL, 'E'}, + {"fqdn", required_argument, NULL, 'F'}, + {"nogateway", no_argument, NULL, 'G'}, + {"sethostname", no_argument, NULL, 'H'}, + {"clientid", optional_argument, NULL, 'I'}, + {"noipv4ll", no_argument, NULL, 'L'}, + {"nomtu", no_argument, NULL, 'M'}, + {"nontp", no_argument, NULL, 'N'}, + {"nodns", no_argument, NULL, 'R'}, + {"msscr", no_argument, NULL, 'S'}, + {"test", no_argument, NULL, 'T'}, + {"nonis", no_argument, NULL, 'Y'}, + {"help", no_argument, &dohelp, 1}, + {"version", no_argument, &doversion, 1}, +#ifdef THERE_IS_NO_FORK + {"daemonised", no_argument, NULL, 'f'}, + {"skiproutes", required_argument, NULL, 'g'}, +#endif + {NULL, 0, NULL, 0} +}; + +#ifdef THERE_IS_NO_FORK +char dhcpcd[PATH_MAX]; +char **dhcpcd_argv = NULL; +int dhcpcd_argc = 0; +char *dhcpcd_skiproutes = NULL; +#undef EXTRA_OPTS +#define EXTRA_OPTS "fg:" +#endif + +static int atoint (const char *s) +{ + char *t; + long n; + + errno = 0; + n = strtol (s, &t, 0); + if ((errno != 0 && n == 0) || s == t || + (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN))) + { + logger (LOG_ERR, "`%s' out of range", s); + return (-1); + } + + return ((int) n); +} + +static pid_t read_pid (const char *pidfile) +{ + FILE *fp; + pid_t pid = 0; + + if ((fp = fopen (pidfile, "r")) == NULL) { + errno = ENOENT; + return 0; + } + + fscanf (fp, "%d", &pid); + fclose (fp); + + + return (pid); +} + +static void usage (void) +{ + printf ("usage: "PACKAGE" [-adknpEGHMNRSTY] [-c script] [-h hostname] [-i classID]\n" + " [-l leasetime] [-m metric] [-r ipaddress] [-s ipaddress]\n" + " [-t timeout] [-u userclass] [-F none | ptr | both]\n" + " [-I clientID] [-q qtsocketaddress] \n"); +} + + +int main (int argc, char **argv) +{ + options_t *options; + int userclasses = 0; + int opt; + int option_index = 0; + char *prefix; + pid_t pid; + int debug = 0; + int i; + int pidfd = -1; + int sig = 0; + int retval = EXIT_FAILURE; + + /* Close any un-needed fd's */ + for (i = getdtablesize() - 1; i >= 3; --i) + close (i); + + openlog (PACKAGE, LOG_PID, LOG_LOCAL0); + + options = xzalloc (sizeof (*options)); + options->script = (char *) DEFAULT_SCRIPT; + snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", + PACKAGE, VERSION); + + options->doarp = true; + options->dodns = true; + options->domtu = true; + options->donis = true; + options->dontp = true; + options->dogateway = true; + options->daemonise = true; + options->doinform = false; + options->doipv4ll = true; + options->doduid = true; + options->timeout = DEFAULT_TIMEOUT; + /* added by Niklas Goby, additional field, storing the socket address path for + * communicating with Qt "server" + * defined in dhcpcd.h */ + strcpy(options->qtsocketaddress, DEFAULT_QTSOCKETADDRESS); + + gethostname (options->hostname, sizeof (options->hostname)); + if (strcmp (options->hostname, "(none)") == 0 || + strcmp (options->hostname, "localhost") == 0) + memset (options->hostname, 0, sizeof (options->hostname)); + + + /* Don't set any optional arguments here so we retain POSIX + * compatibility with getopt */ + while ((opt = getopt_long(argc, argv, EXTRA_OPTS + "c:dh:i:kl:m:npq:r:s:t:u:xAEF:GHI:LMNRSTY", + longopts, &option_index)) != -1) + { + switch (opt) { + case 0: + if (longopts[option_index].flag) + break; + logger (LOG_ERR, + "option `%s' should set a flag", + longopts[option_index].name); + goto abort; + case 'c': + options->script = optarg; + break; + case 'd': + debug++; + switch (debug) { + case 1: + setloglevel (LOG_DEBUG); + break; + case 2: + options->daemonise = false; + break; + } + break; + #ifdef THERE_IS_NO_FORK + case 'f': + options->daemonised = true; + close_fds (); + break; + case 'g': + dhcpcd_skiproutes = xstrdup (optarg); + break; + #endif + case 'h': + if (! optarg) + *options->hostname = '\0'; + else if (strlen (optarg) > MAXHOSTNAMELEN) { + logger (LOG_ERR, + "`%s' too long for HostName string, max is %d", + optarg, MAXHOSTNAMELEN); + goto abort; + } else + strlcpy (options->hostname, optarg, + sizeof (options->hostname)); + break; + case 'i': + if (! optarg) { + *options->classid = '\0'; + } else if (strlen (optarg) > CLASS_ID_MAX_LEN) { + logger (LOG_ERR, + "`%s' too long for ClassID string, max is %d", + optarg, CLASS_ID_MAX_LEN); + goto abort; + } else + strlcpy (options->classid, optarg, + sizeof (options->classid)); + break; + case 'k': + sig = SIGHUP; + break; + case 'l': + if (*optarg == '-') { + logger (LOG_ERR, + "leasetime must be a positive value"); + goto abort; + } + errno = 0; + options->leasetime = (uint32_t) strtol (optarg, NULL, 0); + if (errno == EINVAL || errno == ERANGE) { + logger (LOG_ERR, "`%s' out of range", optarg); + goto abort; + } + break; + case 'm': + options->metric = atoint (optarg); + if (options->metric < 0) { + logger (LOG_ERR, + "metric must be a positive value"); + goto abort; + } + break; + case 'n': + sig = SIGALRM; + break; + case 'p': + options->persistent = true; + break; + case 'q': + if (strlen(optarg) > QTSOCKETADDRESSLENGTH) { + logger(LOG_ERR, "`%s' too long for an socket address path (max=%d)", + optarg, QTSOCKETADDRESSLENGTH); + goto abort; + } + strlcpy(options->qtsocketaddress, optarg, sizeof(options->qtsocketaddress)); + break; + case 's': + options->doinform = true; + options->doarp = false; + if (! optarg || strlen (optarg) == 0) { + options->request_address.s_addr = 0; + break; + } else { + char *slash = strchr (optarg, '/'); + if (slash) { + int cidr; + /* nullify the slash, so the -r option can read the + * address */ + *slash++ = '\0'; + if (sscanf (slash, "%d", &cidr) != 1 || + inet_cidrtoaddr (cidr, &options->request_netmask) != 0) { + logger (LOG_ERR, "`%s' is not a valid CIDR", slash); + goto abort; + } + } + } + /* FALLTHROUGH */ + case 'r': + if (! options->doinform) + options->dorequest = true; + if (strlen (optarg) > 0 && + ! inet_aton (optarg, &options->request_address)) + { + logger (LOG_ERR, "`%s' is not a valid IP address", optarg); + goto abort; + } + break; + case 't': + options->timeout = atoint (optarg); + if (options->timeout < 0) { + logger (LOG_ERR, "timeout must be a positive value"); + goto abort; + } + break; + case 'u': + { + int offset = 0; + for (i = 0; i < userclasses; i++) + offset += (int) options->userclass[offset] + 1; + if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) { + logger (LOG_ERR, "userclass overrun, max is %d", + USERCLASS_MAX_LEN); + goto abort; + } + userclasses++; + memcpy (options->userclass + offset + 1 , optarg, strlen (optarg)); + options->userclass[offset] = strlen (optarg); + options->userclass_len += (strlen (optarg)) + 1; + } + break; + case 'x': + sig = SIGTERM; + break; + case 'A': + #ifndef ENABLE_ARP + logger (LOG_ERR, + "arp not compiled into dhcpcd"); + goto abort; + #endif + options->doarp = false; + break; + case 'E': + #ifndef ENABLE_INFO + logger (LOG_ERR, + "info not compiled into dhcpcd"); + goto abort; + #endif + options->dolastlease = true; + break; + case 'F': + if (strncmp (optarg, "none", strlen (optarg)) == 0) + options->fqdn = FQDN_NONE; + else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) + options->fqdn = FQDN_PTR; + else if (strncmp (optarg, "both", strlen (optarg)) == 0) + options->fqdn = FQDN_BOTH; + else { + logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); + goto abort; + } + break; + case 'G': + options->dogateway = false; + break; + case 'H': + options->dohostname++; + break; + case 'I': + if (optarg) { + if (strlen (optarg) > CLIENT_ID_MAX_LEN) { + logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", + optarg, CLIENT_ID_MAX_LEN); + goto abort; + } + if (strlcpy (options->clientid, optarg, + sizeof (options->clientid)) == 0) + /* empty string disabled duid */ + options->doduid = false; + + } else { + memset (options->clientid, 0, sizeof (options->clientid)); + options->doduid = false; + } + break; + case 'L': + options->doipv4ll = false; + break; + case 'M': + options->domtu = false; + break; + case 'N': + options->dontp = false; + break; + case 'R': + options->dodns = false; + break; + case 'S': + options->domscsr++; + break; + case 'T': + #ifndef ENABLE_INFO + logger (LOG_ERR, "info support not compiled into dhcpcd"); + goto abort; + #endif + options->test = true; + options->persistent = true; + break; + case 'Y': + options->donis = false; + break; + case '?': + usage (); + goto abort; + default: + usage (); + goto abort; + } + } + if (doversion) { + printf (""PACKAGE" "VERSION"\n"); + printf ("Compile time options:" + #ifdef ENABLE_ARP + " ARP" + #endif + #ifdef ENABLE_DUID + " DUID" + #endif + #ifdef ENABLE_INFO + " INFO" + #endif + #ifdef ENABLE_INFO_COMPAT + " INFO_COMPAT" + #endif + #ifdef ENABLE_IPV4LL + " IPV4LL" + #endif + #ifdef ENABLE_NIS + " NIS" + #endif + #ifdef ENABLE_NTP + " NTP" + #endif + #ifdef SERVICE + " " SERVICE + #endif + #ifdef ENABLE_RESOLVCONF + " RESOLVCONF" + #endif + #ifdef THERE_IS_NO_FORK + " THERE_IS_NO_FORK" + #endif + "\n"); + } + + if (dohelp) + usage (); + + +#ifdef THERE_IS_NO_FORK + dhcpcd_argv = argv; + dhcpcd_argc = argc; + if (! realpath (argv[0], dhcpcd)) { + logger (LOG_ERR, "unable to resolve the path `%s': %s", + argv[0], strerror (errno)); + goto abort; + } +#endif + + /* initializations for the ipc connection to qt*/ + setSocketName(options->qtsocketaddress); + if (initQtLoggerSocket() < 0) { + logger(LOG_ERR, "initialization Qt Logger failed: %s ", strerror (errno)); + goto abort; + } + + + if (optind < argc) { + if (strlen(argv[optind]) > IF_NAMESIZE) { + logger(LOG_ERR, "`%s' too long for an interface name (max=%d)", + argv[optind], IF_NAMESIZE); + goto abort; + } + strlcpy(options->interface, argv[optind], sizeof(options->interface)); + setInterfaceName(options->interface); + } else { + /* If only version was requested then exit now */ + if (doversion || dohelp) { + retval = 0; + goto abort; + } + + logger(LOG_ERR, "no interface specified"); + setInterfaceName("no_if"); + goto abort; + } + + if (strchr(options->hostname, '.')) { + if (options->fqdn == FQDN_DISABLE) + options->fqdn = FQDN_BOTH; + } else + options->fqdn = FQDN_DISABLE; + + if (options->request_address.s_addr == 0 && options->doinform) { + if ((options->request_address.s_addr = get_address(options->interface)) + != 0) + options->keep_address = true; + } + + if (IN_LINKLOCAL (ntohl (options->request_address.s_addr))) { + logger (LOG_ERR, + "you are not allowed to request a link local address"); + logToQt(LOG_ERR, -1, "you are not allowed to request a link local address"); + goto abort; + } + + if (geteuid ()) { + logger (LOG_WARNING, PACKAGE " will not work correctly unless" + " run as root"); + } + + prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3)); + snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface); + setlogprefix (prefix); + snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE, + options->interface); + free (prefix); + + chdir ("/"); + umask (022); + + if (mkdir (INFODIR, S_IRUSR | S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP + | S_IROTH | S_IXOTH) && errno != EEXIST) + { + logger (LOG_ERR, + "mkdir(\"%s\",0): %s\n", INFODIR, strerror (errno)); + goto abort; + } + + if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP + | S_IROTH | S_IXOTH) && errno != EEXIST) + { + logger (LOG_ERR, + "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); + goto abort; + } + + if (options->test) { + if (options->dorequest || options->doinform) { + logger (LOG_ERR, + "cannot test with --inform or --request"); + goto abort; + } + + if (options->dolastlease) { + logger (LOG_ERR, "cannot test with --lastlease"); + goto abort; + } + + if (sig != 0) { + logger (LOG_ERR, + "cannot test with --release or --renew"); + goto abort; + } + } + + if (sig != 0) { + int killed = -1; + pid = read_pid (options->pidfile); + if (pid != 0) + logger (LOG_INFO, "sending signal %d to pid %d", + sig, pid); + + if (! pid || (killed = kill (pid, sig))) + logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, + ""PACKAGE" not running"); + + if (pid != 0 && (sig != SIGALRM || killed != 0)) + unlink (options->pidfile); + + if (killed == 0) { + retval = EXIT_SUCCESS; + goto abort; + } + + if (sig != SIGALRM) + goto abort; + } + + if (! options->test && ! options->daemonised) { + if ((pid = read_pid (options->pidfile)) > 0 && + kill (pid, 0) == 0) + { + logger (LOG_ERR, ""PACKAGE + " already running on pid %d (%s)", + pid, options->pidfile); + goto abort; + } + + pidfd = open (options->pidfile, + O_WRONLY | O_CREAT | O_NONBLOCK, 0664); + if (pidfd == -1) { + logger (LOG_ERR, "open `%s': %s", + options->pidfile, strerror (errno)); + goto abort; + } + + /* Lock the file so that only one instance of dhcpcd runs + * on an interface */ + if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) { + logger (LOG_ERR, "flock `%s': %s", + options->pidfile, strerror (errno)); + goto abort; + } + + /* dhcpcd.sh should not interhit this fd */ + if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 || + fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1) + logger (LOG_ERR, "fcntl: %s", strerror (errno)); + + writepid (pidfd, getpid ()); + logger (LOG_INFO, PACKAGE " " VERSION " starting"); + } + + /* Seed random */ + srandomdev (); + + /* Massage our filters per platform */ + setup_packet_filters (); + + /* dhcp_run : defined in client.c */ + if (dhcp_run (options, &pidfd) == 0) + retval = EXIT_SUCCESS; + +abort: + /* If we didn't daemonise then we need to punt the pidfile now */ + if (pidfd > -1) { + close (pidfd); + unlink (options->pidfile); + } + + free (options); + +#ifdef THERE_IS_NO_FORK + /* There may have been an error before the dhcp_run function + * clears this, so just do it here to be safe */ + free (dhcpcd_skiproutes); +#endif + + logger (LOG_INFO, "exiting"); + logToQt(LOG_INFO, DHCPCD_EXIT, "exiting due abort"); + closeQtLoggerSocket(); + exit (retval); + /* NOTREACHED */ +} diff --git a/src/customdhcpcd/dhcpcd.h b/src/customdhcpcd/dhcpcd.h new file mode 100644 index 0000000..c8df616 --- /dev/null +++ b/src/customdhcpcd/dhcpcd.h @@ -0,0 +1,108 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef DHCPCD_H +#define DHCPCD_H + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#include "../../common/fbgui.h" + +#define DEFAULT_TIMEOUT 20 +#define DEFAULT_LEASETIME 3600 /* 1 hour */ + +/* added by Niklas Goby, additional field, storing the socket address path for + * communicating with Qt "server" */ + + +#define QTSOCKETADDRESSLENGTH 255 + +#define CLASS_ID_MAX_LEN 48 +#define CLIENT_ID_MAX_LEN 48 +#define USERCLASS_MAX_LEN 255 + +#ifdef THERE_IS_NO_FORK +extern char dhcpcd[PATH_MAX]; +extern char **dhcpcd_argv; +extern int dhcpcd_argc; +extern char *dhcpcd_skiproutes; +#endif + +typedef struct options_t { + /* added by Niklas Goby, additional field, storing the socket address path for + * communicating with Qt "server" */ + char qtsocketaddress[QTSOCKETADDRESSLENGTH]; + /*----*/ + char interface[IF_NAMESIZE]; + char hostname[MAXHOSTNAMELEN]; + int fqdn; + char classid[CLASS_ID_MAX_LEN]; + char clientid[CLIENT_ID_MAX_LEN]; + char userclass[USERCLASS_MAX_LEN]; + size_t userclass_len; + uint32_t leasetime; + time_t timeout; + int metric; + + bool doarp; + bool dodns; + bool dodomainname; + bool dogateway; + int dohostname; + bool domtu; + bool donis; + bool dontp; + bool dolastlease; + bool doinform; + bool dorequest; + bool doipv4ll; + bool doduid; + int domscsr; + + struct in_addr request_address; + struct in_addr request_netmask; + + bool persistent; + bool keep_address; + bool daemonise; + bool daemonised; + bool test; + + char *script; + char pidfile[PATH_MAX]; +} options_t; + +int nd_main (char *ifname); + +#endif diff --git a/src/customdhcpcd/dhcpcd.sh b/src/customdhcpcd/dhcpcd.sh new file mode 100644 index 0000000..8c86aac --- /dev/null +++ b/src/customdhcpcd/dhcpcd.sh @@ -0,0 +1,46 @@ +#!/bin/sh +# +# This is a sample /etc/dhcpcd.sh script. +# /etc/dhcpcd.sh script is executed by dhcpcd daemon +# any time it configures or shuts down interface. +# The following parameters are passed to dhcpcd.exe script: +# $1 = HostInfoFilePath, e.g "/var/lib/dhcpcd/dhcpcd-eth0.info" +# $2 = "up" if interface has been configured with the same +# IP address as before reboot; +# $2 = "down" if interface has been shut down; +# $2 = "new" if interface has been configured with new IP address; +# +# Sanity checks + +if [ $# -lt 2 ]; then + logger -s -p local0.err -t dhcpcd.sh "wrong usage" + exit 1 +fi + +hostinfo="$1" +state="$2" + +# Reading HostInfo file for configuration parameters +[ -e "${hostinfo}" ] && . "${hostinfo}" + +case "${state}" in + up) + logger -s -p local0.info -t dhcpcd.sh \ + "interface ${INTERFACE} has been configured with old IP=${IPADDR}" + # Put your code here for when the interface has been brought up with an + # old IP address here + ;; + + new) + logger -s -p local0.info -t dhcpcd.sh \ + "interface ${INTERFACE} has been configured with new IP=${IPADDR}" + # Put your code here for when the interface has been brought up with a + # new IP address + ;; + + down) logger -s -p local0.info -t dhcpcd.sh \ + "interface ${INTERFACE} has been brought down" + # Put your code here for the when the interface has been shut down + ;; +esac +exit 0 diff --git a/src/customdhcpcd/discover.c b/src/customdhcpcd/discover.c new file mode 100644 index 0000000..eae7b0a --- /dev/null +++ b/src/customdhcpcd/discover.c @@ -0,0 +1,7 @@ +/* + * discover.c + * + * Created on: Jul 7, 2011 + * Author: niklas + */ + diff --git a/src/customdhcpcd/discover.h b/src/customdhcpcd/discover.h new file mode 100644 index 0000000..1f4918d --- /dev/null +++ b/src/customdhcpcd/discover.h @@ -0,0 +1,12 @@ +/* + * discover.h + * + * Created on: Jul 7, 2011 + * Author: niklas + */ + +#ifndef DISCOVER_H_ +#define DISCOVER_H_ + + +#endif /* DISCOVER_H_ */ diff --git a/src/customdhcpcd/duid.c b/src/customdhcpcd/duid.c new file mode 100644 index 0000000..e4dd83b --- /dev/null +++ b/src/customdhcpcd/duid.c @@ -0,0 +1,118 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "duid.h" +#include "logger.h" + +#ifdef ENABLE_DUID + +#define THIRTY_YEARS_IN_SECONDS 946707779 + +size_t get_duid (unsigned char *duid, const interface_t *iface) +{ + FILE *f; + uint16_t type = 0; + uint16_t hw = 0; + uint32_t ul; + time_t t; + int x = 0; + unsigned char *p = duid; + size_t len = 0; + + if (! iface) + return (0); + + /* If we already have a DUID then use it as it's never supposed + * to change once we have one even if the interfaces do */ + if ((f = fopen (DUIDFILE, "r"))) { + char *line = get_line (f); + if (line) { + len = hwaddr_aton (NULL, line); + if (len && len <= DUID_LEN) + hwaddr_aton (duid, line); + free (line); + } + fclose (f); + if (len) + return (len); + } else { + if (errno != ENOENT) { + logger (LOG_ERR, "fopen `%s': %s", + DUIDFILE, strerror (errno)); + return (0); + } + } + + /* No file? OK, lets make one based on our interface */ + type = htons (1); /* DUI-D-LLT */ + memcpy (p, &type, 2); + p += 2; + + hw = htons (iface->family); + memcpy (p, &hw, 2); + p += 2; + + /* time returns seconds from jan 1 1970, but DUID-LLT is + * seconds from jan 1 2000 modulo 2^32 */ + t = time (NULL) - THIRTY_YEARS_IN_SECONDS; + ul = htonl (t & 0xffffffff); + memcpy (p, &ul, 4); + p += 4; + + /* Finally, add the MAC address of the interface */ + memcpy (p, iface->hwaddr, iface->hwlen); + p += iface->hwlen; + + len = p - duid; + + if (! (f = fopen (DUIDFILE, "w"))) + logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno)); + else { + x = fprintf (f, "%s\n", hwaddr_ntoa (duid, len)); + fclose (f); + } + + /* Failed to write the duid? scrub it, we cannot use it */ + if (x < 1) { + len = 0; + unlink (DUIDFILE); + } + + return (len); +} +#endif diff --git a/src/customdhcpcd/duid.h b/src/customdhcpcd/duid.h new file mode 100644 index 0000000..1492990 --- /dev/null +++ b/src/customdhcpcd/duid.h @@ -0,0 +1,42 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef DUID_H +#define DUID_H + +#include "config.h" + +#ifdef ENABLE_DUID +#ifndef DUID_LEN +# define DUID_LEN 128 + 2 +#endif + +#include "interface.h" + +size_t get_duid (unsigned char *duid, const interface_t *iface); +#endif +#endif diff --git a/src/customdhcpcd/info.c b/src/customdhcpcd/info.c new file mode 100644 index 0000000..8369b43 --- /dev/null +++ b/src/customdhcpcd/info.c @@ -0,0 +1,472 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "dhcp.h" +#include "interface.h" +#include "logger.h" +#include "info.h" + +#ifdef ENABLE_INFO + +/* Create a malloced string of cstr, changing ' to '\'' + * so the contents work in a shell */ +static char *cleanmetas (const char *cstr) +{ + const char *p = cstr; + char *new; + char *n; + size_t len; + + if (cstr == NULL || (len = strlen (cstr)) == 0) + return (xstrdup ("")); + + n = new = xmalloc (sizeof (char) * len + 2); + do + if (*p == '\'') { + size_t pos = n - new; + len += 4; + new = xrealloc (new, sizeof (char) * len + 1); + n = new + pos; + *n++ = '\''; + *n++ = '\\'; + *n++ = '\''; + *n++ = '\''; + } else + *n++ = *p; + while (*p++); + + /* Terminate the sucker */ + *n = '\0'; + + return (new); +} + + +static void print_addresses (FILE *f, const struct address_head *addresses) +{ + const address_t *addr; + + STAILQ_FOREACH (addr, addresses, entries) { + fprintf (f, "%s", inet_ntoa (addr->address)); + if (STAILQ_NEXT (addr, entries)) + fprintf (f, " "); + } +} + +static void print_clean (FILE *f, const char *name, const char *value) +{ + char *clean; + + if (! value) + return; + + clean = cleanmetas (value); + fprintf (f, "%s='%s'\n", name, clean); + free (clean); +} + +bool write_info(const interface_t *iface, const dhcp_t *dhcp, + const options_t *options, bool overwrite) +{ + FILE *f; + route_t *route; + struct stat sb; + + if (options->test) + f = stdout; + else { + if (! overwrite && stat (iface->infofile, &sb) == 0) + return (true); + + logger (LOG_DEBUG, "writing %s", iface->infofile); + if ((f = fopen (iface->infofile, "w")) == NULL) { + logger (LOG_ERR, "fopen `%s': %s", + iface->infofile, strerror (errno)); + return (false); + } + } + + if (dhcp->address.s_addr) { + struct in_addr n; + n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; + fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address)); + fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask)); + fprintf (f, "NETWORK='%s'\n", inet_ntoa (n)); + fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast)); + } + if (dhcp->mtu > 0) + fprintf (f, "MTU='%d'\n", dhcp->mtu); + + if (dhcp->routes) { + bool doneone = false; + fprintf (f, "ROUTES='"); + STAILQ_FOREACH (route, dhcp->routes, entries) { + if (route->destination.s_addr != 0) { + if (doneone) + fprintf (f, " "); + fprintf (f, "%s", inet_ntoa (route->destination)); + fprintf (f, ",%s", inet_ntoa (route->netmask)); + fprintf (f, ",%s", inet_ntoa (route->gateway)); + doneone = true; + } + } + fprintf (f, "'\n"); + + doneone = false; + fprintf (f, "GATEWAYS='"); + STAILQ_FOREACH (route, dhcp->routes, entries) { + if (route->destination.s_addr == 0) { + if (doneone) + fprintf (f, " "); + fprintf (f, "%s", inet_ntoa (route->gateway)); + doneone = true; + } + } + fprintf (f, "'\n"); + } + + print_clean (f, "HOSTNAME", dhcp->hostname); + print_clean (f, "DNSDOMAIN", dhcp->dnsdomain); + print_clean (f, "DNSSEARCH", dhcp->dnssearch); + + if (dhcp->dnsservers) { + fprintf (f, "DNSSERVERS='"); + print_addresses (f, dhcp->dnsservers); + fprintf (f, "'\n"); + } + + if (dhcp->fqdn) { + fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags); + fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1); + fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2); + print_clean (f, "FQDNHOSTNAME", dhcp->fqdn->name); + } + + if (dhcp->ntpservers) { + fprintf (f, "NTPSERVERS='"); + print_addresses (f, dhcp->ntpservers); + fprintf (f, "'\n"); + } + + print_clean (f, "NISDOMAIN", dhcp->nisdomain); + if (dhcp->nisservers) { + fprintf (f, "NISSERVERS='"); + print_addresses (f, dhcp->nisservers); + fprintf (f, "'\n"); + } + + print_clean (f, "ROOTPATH", dhcp->rootpath); + print_clean (f, "SIPSERVERS", dhcp->sipservers); + + if (dhcp->serveraddress.s_addr) + fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); + if (dhcp->servername[0]) + print_clean (f, "DHCPSNAME", dhcp->servername); + + if (! options->doinform && dhcp->address.s_addr) { + if (! options->test) + fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom); + fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime); + fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); + fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); + } + print_clean (f, "INTERFACE", iface->name); + print_clean (f, "CLASSID", options->classid); + if (iface->clientid_len > 0) { + fprintf (f, "CLIENTID='%s'\n", + hwaddr_ntoa (iface->clientid, iface->clientid_len)); + } + fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, + iface->hwlen)); + +#ifdef ENABLE_INFO_COMPAT + /* Support the old .info settings if we need to */ + fprintf (f, "\n# dhcpcd-1.x and 2.x compatible variables\n"); + if (dhcp->dnsservers) { + address_t *addr; + + fprintf (f, "DNS='"); + STAILQ_FOREACH (addr, dhcp->dnsservers, entries) { + fprintf (f, "%s", inet_ntoa (addr->address)); + if (STAILQ_NEXT (addr, entries)) + fprintf (f, ","); + } + fprintf (f, "'\n"); + } + + if (dhcp->routes) { + bool doneone = false; + fprintf (f, "GATEWAY='"); + STAILQ_FOREACH (route, dhcp->routes, entries) { + if (route->destination.s_addr == 0) { + if (doneone) + fprintf (f, ","); + fprintf (f, "%s", inet_ntoa (route->gateway)); + doneone = true; + } + } + fprintf (f, "'\n"); + } +#endif + + if (! options->test) + fclose (f); + return (true); +} + +static bool parse_address (struct in_addr *addr, + const char *value, const char *var) +{ + if (inet_aton (value, addr) == 0) { + logger (LOG_ERR, "%s `%s': %s", var, value, + strerror (errno)); + return (false); + } + return (true); +} + +static bool parse_uint (unsigned int *i, + const char *value, const char *var) +{ + if (sscanf (value, "%u", i) != 1) { + logger (LOG_ERR, "%s `%s': not a valid number", + var, value); + return (false); + } + return (true); +} + +static bool parse_ushort (unsigned short *s, + const char *value, const char *var) +{ + if (sscanf (value, "%hu", s) != 1) { + logger (LOG_ERR, "%s `%s': not a valid number", + var, value); + return (false); + } + return (true); +} + +static struct address_head *parse_addresses (char *value, const char *var) +{ + char *token; + char *p = value; + struct address_head *head = NULL; + + while ((token = strsep (&p, " "))) { + address_t *a = xzalloc (sizeof (*a)); + + if (inet_aton (token, &a->address) == 0) { + logger (LOG_ERR, "%s: invalid address `%s'", var, token); + free_address (head); + free (a); + return (NULL); + } + + if (! head) { + head = xmalloc (sizeof (*head)); + STAILQ_INIT (head); + } + STAILQ_INSERT_TAIL (head, a, entries); + } + + return (head); +} + +bool read_info (const interface_t *iface, dhcp_t *dhcp) +{ + FILE *fp; + char *line; + char *var; + char *value; + char *p; + struct stat sb; + + if (stat (iface->infofile, &sb) != 0) { + logger (LOG_ERR, "lease information file `%s' does not exist", + iface->infofile); + return (false); + } + + if (! (fp = fopen (iface->infofile, "r"))) { + logger (LOG_ERR, "fopen `%s': %s", + iface->infofile, strerror (errno)); + return (false); + } + + dhcp->frominfo = true; + + while ((line = get_line (fp))) { + var = line; + + /* Strip leading spaces/tabs */ + while ((*var == ' ') || (*var == '\t')) + var++; + + /* Trim trailing \n */ + p = var + strlen (var) - 1; + if (*p == '\n') + *p = 0; + + /* Skip comments */ + if (*var == '#') + goto next; + + /* If we don't have an equals sign then skip it */ + if (! (p = strchr (var, '='))) + goto next; + + /* Terminate the = so we have two strings */ + *p = 0; + + value = p + 1; + /* Strip leading and trailing quotes if present */ + if (*value == '\'' || *value == '"') + value++; + p = value + strlen (value) - 1; + if (*p == '\'' || *p == '"') + *p = 0; + + /* Don't process null vars or values */ + if (! *var || ! *value) + goto next; + + if (strcmp (var, "IPADDR") == 0) + parse_address (&dhcp->address, value, "IPADDR"); + else if (strcmp (var, "NETMASK") == 0) + parse_address (&dhcp->netmask, value, "NETMASK"); + else if (strcmp (var, "BROADCAST") == 0) + parse_address (&dhcp->broadcast, value, "BROADCAST"); + else if (strcmp (var, "MTU") == 0) + parse_ushort (&dhcp->mtu, value, "MTU"); + else if (strcmp (var, "ROUTES") == 0) { + p = value; + while ((value = strsep (&p, " "))) { + char *pp = value; + char *dest = strsep (&pp, ","); + char *net = strsep (&pp, ","); + char *gate = strsep (&pp, ","); + route_t *route; + + if (! dest || ! net || ! gate) { + logger (LOG_ERR, "read_info ROUTES `%s,%s,%s': invalid route", + dest, net, gate); + goto next; + } + + /* See if we can create a route */ + route = xzalloc (sizeof (*route)); + if (inet_aton (dest, &route->destination) == 0) { + logger (LOG_ERR, "read_info ROUTES `%s': not a valid destination address", + dest); + free (route); + goto next; + } + if (inet_aton (dest, &route->netmask) == 0) { + logger (LOG_ERR, "read_info ROUTES `%s': not a valid netmask address", + net); + free (route); + goto next; + } + if (inet_aton (dest, &route->gateway) == 0) { + logger (LOG_ERR, "read_info ROUTES `%s': not a valid gateway address", + gate); + free (route); + goto next; + } + + /* OK, now add our route */ + if (! dhcp->routes) { + dhcp->routes = xmalloc (sizeof (*dhcp->routes)); + STAILQ_INIT (dhcp->routes); + } + STAILQ_INSERT_TAIL (dhcp->routes, route, entries); + } + } else if (strcmp (var, "GATEWAYS") == 0) { + p = value; + while ((value = strsep (&p, " "))) { + route_t *route = xzalloc (sizeof (*route)); + if (parse_address (&route->gateway, value, "GATEWAYS")) { + if (! dhcp->routes) { + dhcp->routes = xmalloc (sizeof (*dhcp->routes)); + STAILQ_INIT (dhcp->routes); + } + STAILQ_INSERT_TAIL (dhcp->routes, route, entries); + } else + free (route); + } + } else if (strcmp (var, "HOSTNAME") == 0) + dhcp->hostname = xstrdup (value); + else if (strcmp (var, "DNSDOMAIN") == 0) + dhcp->dnsdomain = xstrdup (value); + else if (strcmp (var, "DNSSEARCH") == 0) + dhcp->dnssearch = xstrdup (value); + else if (strcmp (var, "DNSSERVERS") == 0) + dhcp->dnsservers = parse_addresses (value, "DNSSERVERS"); + else if (strcmp (var, "NTPSERVERS") == 0) + dhcp->ntpservers = parse_addresses (value, "NTPSERVERS"); + else if (strcmp (var, "NISDOMAIN") == 0) + dhcp->nisdomain = xstrdup (value); + else if (strcmp (var, "NISSERVERS") == 0) + dhcp->nisservers = parse_addresses (value, "NISSERVERS"); + else if (strcmp (var, "ROOTPATH") == 0) + dhcp->rootpath = xstrdup (value); + else if (strcmp (var, "DHCPSID") == 0) + parse_address (&dhcp->serveraddress, value, "DHCPSID"); + else if (strcmp (var, "DHCPSNAME") == 0) + strlcpy (dhcp->servername, value, sizeof (dhcp->servername)); + else if (strcmp (var, "LEASEDFROM") == 0) + parse_uint (&dhcp->leasedfrom, value, "LEASEDFROM"); + else if (strcmp (var, "LEASETIME") == 0) + parse_uint (&dhcp->leasetime, value, "LEASETIME"); + else if (strcmp (var, "RENEWALTIME") == 0) + parse_uint (&dhcp->renewaltime, value, "RENEWALTIME"); + else if (strcmp (var, "REBINDTIME") == 0) + parse_uint (&dhcp->rebindtime, value, "REBINDTIME"); + +next: + free (line); + } + + fclose (fp); + return (true); +} + +#endif + diff --git a/src/customdhcpcd/info.h b/src/customdhcpcd/info.h new file mode 100644 index 0000000..22966db --- /dev/null +++ b/src/customdhcpcd/info.h @@ -0,0 +1,42 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef INFO_H +#define INFO_H + +#include "dhcpcd.h" +#include "interface.h" +#include "dhcp.h" + +#ifdef ENABLE_INFO +bool write_info (const interface_t *iface, const dhcp_t *dhcp, + const options_t *options, bool overwrite); + +bool read_info (const interface_t *iface, dhcp_t *dhcp); +#endif + +#endif diff --git a/src/customdhcpcd/interface.c b/src/customdhcpcd/interface.c new file mode 100644 index 0000000..d2ff8d6 --- /dev/null +++ b/src/customdhcpcd/interface.c @@ -0,0 +1,1060 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include + +/* Netlink suff */ +#ifdef __linux__ +#include /* Needed for 2.4 kernels */ +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "dhcp.h" +#include "interface.h" +#include "logger.h" + +void free_address (struct address_head *addresses) +{ + address_t *p; + address_t *n; + + if (! addresses) + return; + + p = STAILQ_FIRST (addresses); + while (p) { + n = STAILQ_NEXT (p, entries); + free (p); + p = n; + } + free (addresses); +} + +void free_route (struct route_head *routes) +{ + route_t *p; + route_t *n; + + if (! routes) + return; + + p = STAILQ_FIRST (routes); + while (p) { + n = STAILQ_NEXT (p, entries); + free (p); + p = n; + } + free (routes); +} + +int inet_ntocidr (struct in_addr address) +{ + int cidr = 0; + uint32_t mask = htonl (address.s_addr); + + while (mask) { + cidr++; + mask <<= 1; + } + + return (cidr); +} + +int inet_cidrtoaddr (int cidr, struct in_addr *addr) { + int ocets; + + if (cidr < 0 || cidr > 32) { + errno = EINVAL; + return (-1); + } + ocets = (cidr + 7) / 8; + + memset (addr, 0, sizeof (*addr)); + if (ocets > 0) { + memset (&addr->s_addr, 255, (size_t) ocets - 1); + memset ((unsigned char *) &addr->s_addr + (ocets - 1), + (256 - (1 << (32 - cidr) % 8)), 1); + } + + return (0); +} + +uint32_t get_netmask (uint32_t addr) +{ + uint32_t dst; + + if (addr == 0) + return (0); + + dst = htonl (addr); + if (IN_CLASSA (dst)) + return (ntohl (IN_CLASSA_NET)); + if (IN_CLASSB (dst)) + return (ntohl (IN_CLASSB_NET)); + if (IN_CLASSC (dst)) + return (ntohl (IN_CLASSC_NET)); + + return (0); +} + +char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen) +{ + static char buffer[(HWADDR_LEN * 3) + 1]; + char *p = buffer; + size_t i; + + for (i = 0; i < hwlen && i < HWADDR_LEN; i++) { + if (i > 0) + *p ++= ':'; + p += snprintf (p, 3, "%.2x", hwaddr[i]); + } + + *p ++= '\0'; + + return (buffer); +} + +size_t hwaddr_aton (unsigned char *buffer, const char *addr) +{ + char c[3]; + const char *p = addr; + unsigned char *bp = buffer; + size_t len = 0; + + c[2] = '\0'; + while (*p) { + c[0] = *p++; + c[1] = *p++; + /* Ensure that next data is EOL or a seperator with data */ + if (! (*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) { + errno = EINVAL; + return (0); + } + /* Ensure that digits are hex */ + if (isxdigit ((int) c[0]) == 0 || isxdigit ((int) c[1]) == 0) { + errno = EINVAL; + return (0); + } + p++; + if (bp) + *bp++ = (unsigned char) strtol (c, NULL, 16); + else + len++; + } + + if (bp) + return (bp - buffer); + return (len); +} + +static int _do_interface (const char *ifname, + _unused unsigned char *hwaddr, _unused size_t *hwlen, + struct in_addr *addr, + bool flush, bool get) +{ + int s; + struct ifconf ifc; + int retval = 0; + int len = 10 * sizeof (struct ifreq); + int lastlen = 0; + char *p; + + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + /* Not all implementations return the needed buffer size for + * SIOGIFCONF so we loop like so for all until it works */ + memset (&ifc, 0, sizeof (ifc)); + for (;;) { + ifc.ifc_len = len; + ifc.ifc_buf = xmalloc ((size_t) len); + if (ioctl (s, SIOCGIFCONF, &ifc) == -1) { + if (errno != EINVAL || lastlen != 0) { + logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", + strerror (errno)); + close (s); + free (ifc.ifc_buf); + return -1; + } + } else { + if (ifc.ifc_len == lastlen) + break; + lastlen = ifc.ifc_len; + } + + free (ifc.ifc_buf); + ifc.ifc_buf = NULL; + len *= 2; + } + + for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) { + union { + char *buffer; + struct ifreq *ifr; + } ifreqs; + struct sockaddr_in address; + struct ifreq *ifr; + + /* Cast the ifc buffer to an ifreq cleanly */ + ifreqs.buffer = p; + ifr = ifreqs.ifr; + +#ifdef __linux__ + p += sizeof (*ifr); +#else + p += offsetof (struct ifreq, ifr_ifru) + ifr->ifr_addr.sa_len; +#endif + + if (strcmp (ifname, ifr->ifr_name) != 0) + continue; + +#ifdef AF_LINK + if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) { + struct sockaddr_dl sdl; + + memcpy (&sdl, &ifr->ifr_addr, sizeof (sdl)); + *hwlen = sdl.sdl_alen; + memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen, + (size_t) sdl.sdl_alen); + retval = 1; + break; + } +#endif + + if (ifr->ifr_addr.sa_family == AF_INET) { + memcpy (&address, &ifr->ifr_addr, sizeof (address)); + if (flush) { + struct sockaddr_in netmask; + + if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) { + logger (LOG_ERR, + "ioctl SIOCGIFNETMASK: %s", + strerror (errno)); + continue; + } + memcpy (&netmask, &ifr->ifr_addr, + sizeof (netmask)); + + if (del_address (ifname, + address.sin_addr, + netmask.sin_addr) == -1) + retval = -1; + } else if (get) { + addr->s_addr = address.sin_addr.s_addr; + retval = 1; + break; + } else if (address.sin_addr.s_addr == addr->s_addr) { + retval = 1; + break; + } + } + + } + + close (s); + free (ifc.ifc_buf); + return retval; +} + +interface_t *read_interface (const char *ifname, _unused int metric) +{ + int s; + struct ifreq ifr; + interface_t *iface = NULL; + unsigned char *hwaddr = NULL; + size_t hwlen = 0; + sa_family_t family = 0; + unsigned short mtu; +#ifdef __linux__ + char *p; +#endif + + if (! ifname) + return NULL; + + memset (&ifr, 0, sizeof (ifr)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return NULL; + } + +#ifdef __linux__ + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) { + logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); + goto exit; + } + + switch (ifr.ifr_hwaddr.sa_family) { + case ARPHRD_ETHER: + case ARPHRD_IEEE802: + hwlen = ETHER_ADDR_LEN; + break; + case ARPHRD_IEEE1394: + hwlen = EUI64_ADDR_LEN; + case ARPHRD_INFINIBAND: + hwlen = INFINIBAND_ADDR_LEN; + break; + default: + logger (LOG_ERR, + "interface is not Ethernet, FireWire, " \ + "InfiniBand or Token Ring"); + goto exit; + } + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); + family = ifr.ifr_hwaddr.sa_family; +#else + ifr.ifr_metric = metric; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) { + logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); + goto exit; + } + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) { + logger (LOG_ERR, "could not find interface %s", ifname); + goto exit; + } + + family = ARPHRD_ETHER; +#endif + + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCGIFMTU, &ifr) == -1) { + logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); + goto exit; + } + + if (ifr.ifr_mtu < MTU_MIN) { + logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", + ifr.ifr_mtu, MTU_MIN); + ifr.ifr_mtu = MTU_MIN; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCSIFMTU, &ifr) == -1) { + logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", + strerror (errno)); + goto exit; + } + } + mtu = ifr.ifr_mtu; + + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); +#ifdef __linux__ + /* We can only bring the real interface up */ + if ((p = strchr (ifr.ifr_name, ':'))) + *p = '\0'; +#endif + if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) { + logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); + goto exit; + } + + if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) { + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (ioctl (s, SIOCSIFFLAGS, &ifr) != 0) { + logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", + strerror (errno)); + goto exit; + } + } + + iface = xzalloc (sizeof (*iface)); + strlcpy (iface->name, ifname, IF_NAMESIZE); +#ifdef ENABLE_INFO + snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); +#endif + memcpy (&iface->hwaddr, hwaddr, hwlen); + iface->hwlen = hwlen; + + iface->family = family; + iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)); + iface->mtu = iface->previous_mtu = mtu; + + logger (LOG_INFO, "hardware address = %s", + hwaddr_ntoa (iface->hwaddr, iface->hwlen)); + + /* 0 is a valid fd, so init to -1 */ + iface->fd = -1; +#ifdef __linux__ + iface->listen_fd = -1; +#endif + +exit: + close (s); + free (hwaddr); + return iface; +} + +int get_mtu (const char *ifname) +{ + struct ifreq ifr; + int r; + int s; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + + memset (&ifr, 0, sizeof (ifr)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + r = ioctl (s, SIOCGIFMTU, &ifr); + close (s); + + if (r == -1) { + logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); + return (-1); + } + + return (ifr.ifr_mtu); +} + +int set_mtu (const char *ifname, short int mtu) +{ + struct ifreq ifr; + int r; + int s; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + + memset (&ifr, 0, sizeof (ifr)); + logger (LOG_DEBUG, "setting MTU to %d", mtu); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + ifr.ifr_mtu = mtu; + r = ioctl (s, SIOCSIFMTU, &ifr); + close (s); + + if (r == -1) + logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno)); + + return (r == 0 ? 0 : -1); +} + +static void log_route (struct in_addr destination, + struct in_addr netmask, + struct in_addr gateway, + _unused int metric, + int change, int del) +{ + char *dstd = xstrdup (inet_ntoa (destination)); + +#ifdef __linux__ +#define METRIC " metric %d" +#else +#define METRIC "" +#endif + + if (gateway.s_addr == destination.s_addr || + gateway.s_addr == INADDR_ANY) + logger (LOG_INFO, "%s route to %s/%d" METRIC, + change ? "changing" : del ? "removing" : "adding", + dstd, inet_ntocidr (netmask) +#ifdef __linux__ + , metric +#endif + ); + else if (destination.s_addr == INADDR_ANY) + logger (LOG_INFO, "%s default route via %s" METRIC, + change ? "changing" : del ? "removing" : "adding", + inet_ntoa (gateway) + +#ifdef __linux__ + , metric +#endif + ); + else + logger (LOG_INFO, "%s route to %s/%d via %s" METRIC, + change ? "changing" : del ? "removing" : "adding", + dstd, inet_ntocidr (netmask), inet_ntoa (gateway) +#ifdef __linux__ + , metric +#endif + ); + + free (dstd); +} + +#if defined(BSD) || defined(__FreeBSD_kernel__) + +/* Darwin doesn't define this for some very odd reason */ +#ifndef SA_SIZE +# define SA_SIZE(sa) \ + ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ + sizeof(long) : \ + 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) +#endif + +static int do_address (const char *ifname, struct in_addr address, + struct in_addr netmask, struct in_addr broadcast, + int del) +{ + int s; + struct ifaliasreq ifa; + + if (! ifname) + return -1; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&ifa, 0, sizeof (ifa)); + strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name)); + +#define ADDADDR(_var, _addr) { \ + union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \ + _s.sa = &_var; \ + _s.sin->sin_family = AF_INET; \ + _s.sin->sin_len = sizeof (*_s.sin); \ + memcpy (&_s.sin->sin_addr, &_addr, sizeof (_s.sin->sin_addr)); \ +} + + ADDADDR (ifa.ifra_addr, address); + ADDADDR (ifa.ifra_mask, netmask); +if (! del) + ADDADDR (ifa.ifra_broadaddr, broadcast); + +#undef ADDADDR + + if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) { + logger (LOG_ERR, "ioctl %s: %s", + del ? "SIOCDIFADDR" : "SIOCAIFADDR", + strerror (errno)); + close (s); + return -1; + } + +close (s); +return 0; +} + +static int do_route (const char *ifname, + struct in_addr destination, + struct in_addr netmask, + struct in_addr gateway, + int metric, + int change, int del) +{ + int s; + static int seq; + union sockunion { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef INET6 + struct sockaddr_in6 sin6; +#endif + struct sockaddr_dl sdl; + struct sockaddr_storage ss; + } su; + struct rtm + { + struct rt_msghdr hdr; + char buffer[sizeof (su) * 3]; + } rtm; + char *bp = rtm.buffer; + size_t l; + + if (! ifname) + return -1; + + log_route (destination, netmask, gateway, metric, change, del); + + if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&rtm, 0, sizeof (rtm)); + + rtm.hdr.rtm_version = RTM_VERSION; + rtm.hdr.rtm_seq = ++seq; + rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD; + rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC; + + /* This order is important */ + rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; + +#define ADDADDR(_addr) \ + memset (&su, 0, sizeof (su)); \ + su.sin.sin_family = AF_INET; \ + su.sin.sin_len = sizeof (su.sin); \ + memcpy (&su.sin.sin_addr, &_addr, sizeof (su.sin.sin_addr)); \ + l = SA_SIZE (&(su.sa)); \ + memcpy (bp, &(su), l); \ + bp += l; + + ADDADDR (destination); + + if (netmask.s_addr == INADDR_BROADCAST || + gateway.s_addr == INADDR_ANY) + { + /* Make us a link layer socket */ + unsigned char *hwaddr; + size_t hwlen = 0; + + if (netmask.s_addr == INADDR_BROADCAST) + rtm.hdr.rtm_flags |= RTF_HOST; + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); + memset (&su, 0, sizeof (su)); + su.sdl.sdl_len = sizeof (su.sdl); + su.sdl.sdl_family = AF_LINK; + su.sdl.sdl_nlen = strlen (ifname); + memcpy (&su.sdl.sdl_data, ifname, (size_t) su.sdl.sdl_nlen); + su.sdl.sdl_alen = hwlen; + memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, + hwaddr, (size_t) su.sdl.sdl_alen); + + l = SA_SIZE (&(su.sa)); + memcpy (bp, &su, l); + bp += l; + free (hwaddr); + } else { + rtm.hdr.rtm_flags |= RTF_GATEWAY; + ADDADDR (gateway); + } + + ADDADDR (netmask); +#undef ADDADDR + + rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; + if (write (s, &rtm, l) == -1) { + /* Don't report error about routes already existing */ + if (errno != EEXIST) + logger (LOG_ERR, "write: %s", strerror (errno)); + close (s); + return -1; + } + + close (s); + return 0; +} + +#elif __linux__ +/* This netlink stuff is overly compex IMO. + * The BSD implementation is much cleaner and a lot less code. + * send_netlink handles the actual transmission so we can work out + * if there was an error or not. */ +#define BUFFERLEN 256 +int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg) +{ + int s; + pid_t mypid = getpid (); + struct sockaddr_nl nl; + struct iovec iov; + struct msghdr msg; + static unsigned int seq; + char *buffer; + ssize_t bytes; + union + { + char *buffer; + struct nlmsghdr *nlm; + } h; + + if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&nl, 0, sizeof (nl)); + nl.nl_family = AF_NETLINK; + if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (s); + return -1; + } + + memset (&iov, 0, sizeof (iov)); + iov.iov_base = hdr; + iov.iov_len = hdr->nlmsg_len; + + memset (&msg, 0, sizeof (msg)); + msg.msg_name = &nl; + msg.msg_namelen = sizeof (nl); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + /* Request a reply */ + hdr->nlmsg_flags |= NLM_F_ACK; + hdr->nlmsg_seq = ++seq; + + if (sendmsg (s, &msg, 0) == -1) { + logger (LOG_ERR, "write: %s", strerror (errno)); + close (s); + return -1; + } + + buffer = xzalloc (sizeof (char) * BUFFERLEN); + iov.iov_base = buffer; + + for (;;) { + iov.iov_len = BUFFERLEN; + bytes = recvmsg (s, &msg, 0); + + if (bytes == -1) { + if (errno != EINTR) + logger (LOG_ERR, "recvmsg: %s", + strerror (errno)); + continue; + } + + if (bytes == 0) { + logger (LOG_ERR, "netlink: EOF"); + goto eexit; + } + + if (msg.msg_namelen != sizeof (nl)) { + logger (LOG_ERR, + "netlink: sender address length mismatch"); + goto eexit; + } + + for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) { + int len = h.nlm->nlmsg_len; + int l = len - sizeof (*h.nlm); + struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); + + if (l < 0 || len > bytes) { + if (msg.msg_flags & MSG_TRUNC) + logger (LOG_ERR, "netlink: truncated message"); + else + logger (LOG_ERR, "netlink: malformed message"); + goto eexit; + } + + /* Ensure it's our message */ + if (nl.nl_pid != 0 || + (pid_t) h.nlm->nlmsg_pid != mypid || + h.nlm->nlmsg_seq != seq) + { + /* Next Message */ + bytes -= NLMSG_ALIGN (len); + h.buffer += NLMSG_ALIGN (len); + continue; + } + + /* We get an NLMSG_ERROR back with a code of zero for success */ + if (h.nlm->nlmsg_type != NLMSG_ERROR) { + logger (LOG_ERR, "netlink: unexpected reply %d", + h.nlm->nlmsg_type); + goto eexit; + } + + if ((unsigned) l < sizeof (*err)) { + logger (LOG_ERR, "netlink: error truncated"); + goto eexit; + } + + if (err->error == 0) { + int retval = 0; + + close (s); + if (callback) { + if ((retval = callback (hdr, arg)) == -1) + logger (LOG_ERR, "netlink: callback failed"); + } + free (buffer); + return (retval); + } + + errno = -err->error; + /* Don't report on something already existing */ + if (errno != EEXIST) + logger (LOG_ERR, "netlink: %s", + strerror (errno)); + goto eexit; + } + } + +eexit: + close (s); + free (buffer); + return -1; +} + +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) + +static int add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type, + const void *data, int alen) +{ + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) { + logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n", + maxlen); + return -1; + } + + rta = NLMSG_TAIL (n); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA (rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len); + + return 0; +} + +static int add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, + uint32_t data) +{ + int len = RTA_LENGTH (sizeof (data)); + struct rtattr *rta; + + if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) { + logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", + maxlen); + return -1; + } + + rta = NLMSG_TAIL (n); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA (rta), &data, sizeof (data)); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; + + return 0; +} + +struct nlma +{ + struct nlmsghdr hdr; + struct ifaddrmsg ifa; + char buffer[64]; +}; + +struct nlmr +{ + struct nlmsghdr hdr; + struct rtmsg rt; + char buffer[256]; +}; + +static int do_address(const char *ifname, + struct in_addr address, struct in_addr netmask, + struct in_addr broadcast, int del) +{ + struct nlma *nlm; + int retval; + + if (!ifname) + return -1; + + nlm = xzalloc (sizeof (*nlm)); + nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); + nlm->hdr.nlmsg_flags = NLM_F_REQUEST; + if (! del) + nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; + nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; + if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) { + logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", + ifname); + free (nlm); + return -1; + } + nlm->ifa.ifa_family = AF_INET; + + nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask); + + /* This creates the aliased interface */ + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LABEL, + ifname, strlen (ifname) + 1); + + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LOCAL, + &address.s_addr, sizeof (address.s_addr)); + if (! del) + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST, + &broadcast.s_addr, sizeof (broadcast.s_addr)); + + retval = send_netlink (&nlm->hdr, NULL, NULL); + free (nlm); + return retval; +} + +static int do_route (const char *ifname, + struct in_addr destination, + struct in_addr netmask, + struct in_addr gateway, + int metric, int change, int del) +{ + struct nlmr *nlm; + unsigned int ifindex; + int retval; + + if (! ifname) + return -1; + + log_route (destination, netmask, gateway, metric, change, del); + + if (! (ifindex = if_nametoindex (ifname))) { + logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", + ifname); + return -1; + } + + nlm = xzalloc (sizeof (*nlm)); + nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + if (change) + nlm->hdr.nlmsg_flags = NLM_F_REPLACE; + else if (! del) + nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; + nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; + nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; + nlm->rt.rtm_family = AF_INET; + nlm->rt.rtm_table = RT_TABLE_MAIN; + + if (del) + nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; + else { + nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + nlm->rt.rtm_protocol = RTPROT_BOOT; + if (netmask.s_addr == INADDR_BROADCAST || + gateway.s_addr == INADDR_ANY) + nlm->rt.rtm_scope = RT_SCOPE_LINK; + else + nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; + nlm->rt.rtm_type = RTN_UNICAST; + } + + nlm->rt.rtm_dst_len = inet_ntocidr (netmask); + add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_DST, + &destination.s_addr, sizeof (destination.s_addr)); + if (netmask.s_addr != INADDR_BROADCAST && + destination.s_addr != gateway.s_addr) + add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_GATEWAY, + &gateway.s_addr, sizeof (gateway.s_addr)); + + add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex); + add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric); + + retval = send_netlink (&nlm->hdr, NULL, NULL); + free (nlm); + return retval; +} + +#else + #error "Platform not supported!" + #error "We currently support BPF and Linux sockets." + #error "Other platforms may work using BPF. If yours does, please let me know" + #error "so I can add it to our list." +#endif + +int add_address (const char *ifname, struct in_addr address, + struct in_addr netmask, struct in_addr broadcast) +{ + logger (LOG_INFO, "adding IP address %s/%d", + inet_ntoa (address), inet_ntocidr (netmask)); + + return (do_address (ifname, address, netmask, broadcast, 0)); +} + +int del_address (const char *ifname, + struct in_addr address, struct in_addr netmask) +{ + struct in_addr t; + + logger (LOG_INFO, "removing IP address %s/%d", + inet_ntoa (address), inet_ntocidr (netmask)); + + memset (&t, 0, sizeof (t)); + return (do_address (ifname, address, netmask, t, 1)); +} + +int add_route (const char *ifname, struct in_addr destination, + struct in_addr netmask, struct in_addr gateway, int metric) +{ + return (do_route (ifname, destination, netmask, gateway, metric, 0, 0)); +} + +int change_route (const char *ifname, struct in_addr destination, + struct in_addr netmask, struct in_addr gateway, int metric) +{ + return (do_route (ifname, destination, netmask, gateway, metric, 1, 0)); +} + +int del_route (const char *ifname, struct in_addr destination, + struct in_addr netmask, struct in_addr gateway, int metric) +{ + return (do_route (ifname, destination, netmask, gateway, metric, 0, 1)); +} + + +int flush_addresses (const char *ifname) +{ + return (_do_interface (ifname, NULL, NULL, NULL, true, false)); +} + +in_addr_t get_address (const char *ifname) +{ + struct in_addr address; + if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0) + return (address.s_addr); + return (0); +} + +int has_address (const char *ifname, struct in_addr address) +{ + return (_do_interface (ifname, NULL, NULL, &address, false, false)); +} diff --git a/src/customdhcpcd/interface.h b/src/customdhcpcd/interface.h new file mode 100644 index 0000000..8215d48 --- /dev/null +++ b/src/customdhcpcd/interface.h @@ -0,0 +1,173 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef INTERFACE_H +#define INTERFACE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#ifdef __linux__ +# include +#endif + +#ifdef ENABLE_DUID +#ifndef DUID_LEN +# define DUID_LEN 128 + 2 +#endif +#endif + +#define EUI64_ADDR_LEN 8 +#define INFINIBAND_ADDR_LEN 20 + +/* Linux 2.4 doesn't define this */ +#ifndef ARPHRD_IEEE1394 +# define ARPHRD_IEEE1394 24 +#endif + +/* The BSD's don't define this yet */ +#ifndef ARPHRD_INFINIBAND +# define ARPHRD_INFINIBAND 32 +#endif + +#define HWADDR_LEN 20 + +/* Work out if we have a private address or not + * 10/8 + * 172.16/12 + * 192.168/16 + */ +#ifndef IN_PRIVATE +# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \ + ((addr & 0xfff00000) == 0xac100000) || \ + ((addr & IN_CLASSB_NET) == 0xc0a80000)) +#endif + +#define LINKLOCAL_ADDR 0xa9fe0000 +#define LINKLOCAL_MASK 0xffff0000 +#define LINKLOCAL_BRDC 0xa9feffff + +#ifndef IN_LINKLOCAL +# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR) +#endif + +#ifndef STAILQ_ENTRY +# error "your sys/queue.h is too old and lacks STAILQ" +#endif + +#define NSTAILQ_FOREACH(var, head, field) \ + if (head) STAILQ_FOREACH (var, head, field) + +typedef struct route_t +{ + struct in_addr destination; + struct in_addr netmask; + struct in_addr gateway; + STAILQ_ENTRY (route_t) entries; +} route_t; +STAILQ_HEAD (route_head, route_t); + +typedef struct address_t +{ + struct in_addr address; + STAILQ_ENTRY (address_t) entries; +} address_t; +STAILQ_HEAD (address_head, address_t); + +typedef struct interface_t +{ + char name[IF_NAMESIZE]; + sa_family_t family; + unsigned char hwaddr[HWADDR_LEN]; + size_t hwlen; + bool arpable; + unsigned short mtu; + + int fd; + size_t buffer_length; + +#ifdef __linux__ + int listen_fd; + int socket_protocol; +#endif + + char infofile[PATH_MAX]; + + unsigned short previous_mtu; + struct in_addr previous_address; + struct in_addr previous_netmask; + struct route_head *previous_routes; + + time_t start_uptime; + + unsigned char *clientid; + size_t clientid_len; +} interface_t; + +void free_address (struct address_head *addresses); +void free_route (struct route_head *routes); +uint32_t get_netmask (uint32_t addr); +char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen); +size_t hwaddr_aton (unsigned char *hwaddr, const char *addr); + +interface_t *read_interface (const char *ifname, int metric); +int get_mtu (const char *ifname); +int set_mtu (const char *ifname, short int mtu); + +int add_address (const char *ifname, struct in_addr address, + struct in_addr netmask, struct in_addr broadcast); +int del_address (const char *ifname, struct in_addr address, + struct in_addr netmask); + +int flush_addresses (const char *ifname); +in_addr_t get_address (const char *ifname); +int has_address (const char *ifname, struct in_addr address); + +int add_route (const char *ifname, struct in_addr destination, + struct in_addr netmask, struct in_addr gateway, int metric); +int change_route (const char *ifname, struct in_addr destination, + struct in_addr netmask, struct in_addr gateway, int metric); +int del_route (const char *ifname, struct in_addr destination, + struct in_addr netmask, struct in_addr gateway, int metric); + +int inet_ntocidr (struct in_addr address); +int inet_cidrtoaddr (int cidr, struct in_addr *addr); + +#ifdef __linux__ +typedef int (*netlink_callback) (struct nlmsghdr *hdr, void *arg); +int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg); +#endif +#endif diff --git a/src/customdhcpcd/ipv4ll.c b/src/customdhcpcd/ipv4ll.c new file mode 100644 index 0000000..9742b9a --- /dev/null +++ b/src/customdhcpcd/ipv4ll.c @@ -0,0 +1,70 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "config.h" +#include "arp.h" +#include "ipv4ll.h" + +#ifdef ENABLE_IPV4LL + +#ifndef ENABLE_ARP + # error IPV4LL requires ARP +#endif + +#define IPV4LL_LEASETIME 20 + +int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp) { + struct in_addr addr; + + for (;;) { + addr.s_addr = htonl (LINKLOCAL_ADDR | + (((uint32_t) abs ((int) random ()) + % 0xFD00) + 0x0100)); + errno = 0; + if (! arp_claim (iface, addr)) + break; + /* Our ARP may have been interrupted */ + if (errno) + return (-1); + } + + dhcp->address.s_addr = addr.s_addr; + dhcp->netmask.s_addr = htonl (LINKLOCAL_MASK); + dhcp->broadcast.s_addr = htonl (LINKLOCAL_BRDC); + + /* Finally configure some DHCP like lease times */ + dhcp->leasetime = IPV4LL_LEASETIME; + dhcp->renewaltime = (dhcp->leasetime * 0.5); + dhcp->rebindtime = (dhcp->leasetime * 0.875); + + return (0); +} + +#endif diff --git a/src/customdhcpcd/ipv4ll.h b/src/customdhcpcd/ipv4ll.h new file mode 100644 index 0000000..4fa8943 --- /dev/null +++ b/src/customdhcpcd/ipv4ll.h @@ -0,0 +1,39 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IPV4LL_H +#define IPV4LL_H + +#ifdef ENABLE_IPV4LL + +#include "dhcp.h" +#include "interface.h" + +int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp); + +#endif +#endif diff --git a/src/customdhcpcd/logger.c b/src/customdhcpcd/logger.c new file mode 100644 index 0000000..2c8431d --- /dev/null +++ b/src/customdhcpcd/logger.c @@ -0,0 +1,154 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define SYSLOG_NAMES + +#define COM_CH "/var/tmp/com.socket" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "logger.h" +#include "logwriter.h" + +static int loglevel = LOG_WARNING; +static char logprefix[12] = { 0 }; + +int logtolevel(const char *priority) { + CODE *c; + + if (isdigit ((int) *priority)) + return (atoi(priority)); + + for (c = prioritynames; c->c_name; c++) + if (!strcasecmp(priority, c->c_name)) + return (c->c_val); + + return (-1); +} + +static const char *leveltolog(int level) { + CODE *c; + + for (c = prioritynames; c->c_name; c++) + if (c->c_val == level) + return (c->c_name); + + return (NULL); +} + +void setloglevel(int level) { + loglevel = level; +} + +void setlogprefix(const char *prefix) { + snprintf(logprefix, sizeof(logprefix), "%s", prefix); +} + +void logger(int level, const char *fmt, ...) { + va_list p; + //va_list p2; +// FILE *f = stderr; + FILE *f; + FILE *f2; + char* path = "/tmp/cdhcpcd.log"; + char* msgpath = "/tmp/cdhcpcd-msg.log"; + int size = 512; + char *msg = (char *) malloc (size); + + + f = fopen(path,"a"); + f2 = fopen(msgpath,"a"); + va_start (p, fmt); + //va_copy (p2, p); + + + vsnprintf (msg, size, fmt, p); + strcat(msg,"\n"); + logToQt(level, DHCPCD_LOG, msg); + + fprintf(f2, "%s, %s", leveltolog(level), logprefix); + fprintf(f2, "%s", msg); + fputc('\n', f2); + + fprintf(f, "%s, %s", leveltolog(level), logprefix); + vfprintf(f, fmt, p); + fputc('\n', f); + + /* stdout, stderr may be re-directed to some kind of buffer. + * So we always flush to ensure it's written. */ + fflush(f); + +// //logLoggerToQt(level, fmt, p); +// if (level <= LOG_ERR || level <= loglevel) { +// +// /* new function by Niklas Goby +// * send the log message also to our Qt programm. +// * implemented in logwriter.c +// * */ +// //logLoggerToQt(level, fmt, p); +// +// if (level == LOG_DEBUG || level == LOG_INFO) +// f = stdout; +// fprintf(f, "%s, %s", leveltolog(level), logprefix); +// vfprintf(f, fmt, p); +// fputc('\n', f); +// +// /* stdout, stderr may be re-directed to some kind of buffer. +// * So we always flush to ensure it's written. */ +// fflush(f); +// } +// if (level < LOG_DEBUG || level <= loglevel) { +// size_t len = strlen(logprefix); +// size_t fmt2len = strlen(fmt) + len + 1; +// char *fmt2 = malloc(sizeof(char) * fmt2len); +// char *pf = fmt2; +// if (fmt2) { +// memcpy(pf, logprefix, len); +// pf += len; +// strlcpy(pf, fmt, fmt2len - len); +// vsyslog(level, fmt2, p2); +// free(fmt2); +// } else { +// vsyslog(level, fmt, p2); +// syslog(LOG_ERR, "logger: memory exhausted"); +// exit(EXIT_FAILURE); +// } +// } + + //va_end (p2); + va_end (p); +} + diff --git a/src/customdhcpcd/logger.h b/src/customdhcpcd/logger.h new file mode 100644 index 0000000..70e2ed5 --- /dev/null +++ b/src/customdhcpcd/logger.h @@ -0,0 +1,48 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef LOGGER_H +#define LOGGER_H + +#if defined(__GNUC__) +# define _PRINTF_LIKE(_one, _two) __attribute__ ((__format__ (__printf__, _one, _two))) +#else +# define _PRINTF_LIKE(_one, _two) +#endif + +#include + + + +int logtolevel (const char *priority); +void setloglevel (int level); +void setlogprefix (const char *prefix); +void logger (int level, const char *fmt, ...) _PRINTF_LIKE (2, 3); + + + +#endif diff --git a/src/customdhcpcd/logwriter.c b/src/customdhcpcd/logwriter.c new file mode 100644 index 0000000..6230d4c --- /dev/null +++ b/src/customdhcpcd/logwriter.c @@ -0,0 +1,260 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "dhcp.h" +#include "dhcpcd.h" +#include "errno.h" +#include "info.h" +#include "logger.h" +#include "logwriter.h" + +#include "../../common/fbgui.h" // for constants +/*sockets for the logger and the qt-reader */ +int sockfd, ns; +int retval = -1; +char socketName[QTSOCKETADDRESSLENGTH]; +char interfaceName[IF_NAMESIZE]; + +void setSocketName(const char * sn) { + snprintf(socketName, sizeof(socketName), "%s", sn); +} + +void setInterfaceName(const char * in) { + snprintf(interfaceName, sizeof(interfaceName), "%s", in); +} + +int initQtLoggerSocket() { + /** + * new code. seems to be right. + */ + + struct sockaddr_un serv_addr; + fprintf(stdout, "start init \n"); + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) { + fprintf(stdout, "ERROR opening socket \n"); + retval = sockfd; + return sockfd; + } + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, socketName); + + retval = connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); + if (retval < 0) + fprintf(stdout, "ERROR connecting \n"); + fprintf(stdout, "init Qt Logger Socket done \n"); + return retval; +} + +void closeQtLoggerSocket() { + close(sockfd); +} + +void sendToQt(log_msg * msg) { + int n = -1; + int t; + int ret; + const char *tpl = "%s;%d;%d;%s\n"; + char outbuf[DHCP_MESSAGE_SIZE]; + char ack[ACK_SIZE]; + /* + size_t outbuf_size = sizeof(char) * 4 + // ";" *3 + newline + sizeof(int) * 2 + // status, substatus + sizeof(msg->device) + // devicename + sizeof(msg->msg); // msg + outbuf = malloc(outbuf_size); + memset(outbuf, 0, outbuf_size); + snprintf(outbuf, sizeof(char) * 3 + sizeof(int) * 2 + sizeof(msg->device) + + sizeof(msg->msg), tpl, msg->device, msg->status, msg->substatus, + msg->msg); + */ + memset(outbuf, '\0', DHCP_MESSAGE_SIZE); + ret = snprintf(outbuf, DHCP_MESSAGE_SIZE, tpl, msg->device, msg->status, + msg->substatus, msg->msg); + if (ret < 1) { + log ger(LOG_INFO, "[fbgui] ERROR filling message buffer"); + //syslog(LOG_INFO, "[fbgui] ERROR filling message buffer"); + return; + } + if (outbuf != NULL) { + n = send(sockfd, outbuf, DHCP_MESSAGE_SIZE, 0); + } + syslog(LOG_INFO, "[fbgui] INFO writing to socket: [%d:%d] %s (%s)", + msg->status, msg->substatus, msg->msg, msg->device); + + if (n <= 0) { + logger(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)", + msg->status, msg->substatus, msg->msg, msg->device); + //syslog(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)", + // msg->status, msg->substatus, msg->msg, msg->device); + } + /* + memset(ack, 0, ACK_SIZE); + if ((t = recv(sockfd, ack, ACK_SIZE, 0)) > 0) { + syslog(LOG_ERR, "[fbgui] recv ack echo> %s", ack); + printf("received: %s\n", ack); + } else { + if (t < 0) + syslog(LOG_ERR, "[fbgui] ERROR receiving from socket"); + else + syslog(LOG_ERR, "[fbgui] ERROR Server closed"); + } + */ +} + + + +void logToQt(int status, int substatus, const char * msg) { + if (retval >= 0) { + log_msg lm; + lm.status = status; + lm.substatus = substatus; + snprintf(lm.msg, sizeof(lm.msg), "%s", msg); + snprintf(lm.device, sizeof(lm.device), "%s", interfaceName); + sendToQt(&lm); + } +} + + + +void logSendToQt(int type) { + switch (type) { + case DHCP_DISCOVER: + logToQt(LOG_INFO, DHCP_DISCOVER, "send discover"); + break; + case DHCP_OFFER: + logToQt(LOG_INFO, DHCP_OFFER, "send offer"); + break; + case DHCP_REQUEST: + logToQt(LOG_INFO, DHCP_REQUEST, "send request"); + break; + case DHCP_DECLINE: + logToQt(LOG_INFO, DHCP_DECLINE, "send decline"); + break; + case DHCP_ACK: + logToQt(LOG_INFO, DHCP_ACK, "send ack"); + break; + case DHCP_NAK: + logToQt(LOG_INFO, DHCP_NAK, "send nak"); + break; + case DHCP_RELEASE: + logToQt(LOG_INFO, DHCP_RELEASE, "send release"); + break; + case DHCP_INFORM: + logToQt(LOG_INFO, DHCP_INFORM, "send inform"); + break; + default: + break; + } +} + + + +static void print_addresses (FILE *f, const struct address_head *addresses) +{ + const address_t *addr; + + STAILQ_FOREACH (addr, addresses, entries) { + fprintf (f, "%s", inet_ntoa (addr->address)); + if (STAILQ_NEXT (addr, entries)) + fprintf (f, " "); + } +} + + + +void logGatewayToFile(const interface_t *iface, const dhcp_t *dhcp) { + /*void logGatewayToFile(const interface_t iface, const dhcp_t *dhcp, + const options_t options)*/ + //char path[QTSOCKETADDRESSLENGTH]; + + /* + strcpy(path, DEFAULT_GATEWAY_INFO_LOCATION); + strcat(path, iface.name); + strcpy(iface.infofile, path); + options.test = false; + syslog(LOG_INFO, "[fbgui] try to open file: %s", iface.infofile); + write_info(&iface, dhcp, &options, true); + */ + FILE *f; + route_t *route; + char path[QTSOCKETADDRESSLENGTH]; + + strcpy(path, DEFAULT_INTERFACE_CONF_LOCATION); + strcat(path, iface->name); + + syslog(LOG_INFO, "[fbgui] try to open file: %s", path); + + logger(LOG_DEBUG, "writing %s", iface->infofile); + if ((f = fopen(path, "w")) == NULL) { + logger(LOG_ERR, "fopen `%s': %s", path, strerror(errno)); + //TODO: exit/return .. + return; + } + + if (dhcp->address.s_addr) { + struct in_addr n; + n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; + fprintf(f, "IPADDR='%s'\n", inet_ntoa(dhcp->address)); + fprintf(f, "NETMASK='%s'\n", inet_ntoa(dhcp->netmask)); + fprintf(f, "NETWORK='%s'\n", inet_ntoa(n)); + fprintf(f, "BROADCAST='%s'\n", inet_ntoa(dhcp->broadcast)); + } + + if (dhcp->routes) { + bool doneone = false; + fprintf(f, "ROUTES='"); + STAILQ_FOREACH (route, dhcp->routes, entries) { + if (route->destination.s_addr != 0) { + if (doneone) + fprintf(f, " "); + fprintf(f, "%s", inet_ntoa(route->destination)); + fprintf(f, ",%s", inet_ntoa(route->netmask)); + fprintf(f, ",%s", inet_ntoa(route->gateway)); + doneone = true; + } + } + fprintf(f, "'\n"); + + doneone = false; + fprintf(f, "GATEWAYS='"); + STAILQ_FOREACH (route, dhcp->routes, entries) { + if (route->destination.s_addr == 0) { + if (doneone) + fprintf(f, " "); + fprintf(f, "%s", inet_ntoa(route->gateway)); + doneone = true; + } + } + fprintf(f, "'\n"); + } + + fprintf(f, "HOSTNAME='%s", dhcp->hostname); + fprintf(f, "'\n"); + fprintf(f, "DNSSEARCH='%s", dhcp->dnssearch); + fprintf(f, "'\n"); + + if (dhcp->dnsservers) { + fprintf(f, "DNSSERVERS='"); + print_addresses(f, dhcp->dnsservers); + fprintf(f, "'\n"); + } + fprintf(f, "INTERFACE='%s", iface->name); + fprintf(f, "'\n"); + if (iface->clientid_len > 0) { + fprintf(f, "CLIENTID='%s'\n", hwaddr_ntoa(iface->clientid, + iface->clientid_len)); + } + fprintf(f, "DHCPCHADDR='%s'\n", hwaddr_ntoa(iface->hwaddr, iface->hwlen)); + fclose(f); +} diff --git a/src/customdhcpcd/logwriter.h b/src/customdhcpcd/logwriter.h new file mode 100644 index 0000000..43f35fa --- /dev/null +++ b/src/customdhcpcd/logwriter.h @@ -0,0 +1,40 @@ +/* + * logwriter.h + * + * Created on: Jul 7, 2011 + * Author: niklas + */ + +#ifndef LOGWRITER_H_ +#define LOGWRITER_H_ + +#include +#include "dhcp.h" +#include "interface.h" +#include "dhcpcd.h" + +#define LOG_MSG_SIZE 1024 + +typedef struct _log_msg log_msg; +struct _log_msg { + int status; + int substatus; + char device[IF_NAMESIZE]; + char msg[LOG_MSG_SIZE]; +}; + +/** + * new functions for communicating with Qt + */ +void setSocketName(const char * sn); +void setInterfaceName(const char * in); +int initQtLoggerSocket (); +void closeQtLoggerSocket (); +void sendToQt (); +void logToQt(int status, int substatus, const char * msg); +void logSendToQt(int type); +void logLoggerToQt(int level, const char *fmt, ...); +//void logToQt(char * status, char * substatus, char * msg); +void logGatewayToFile(const interface_t *iface, const dhcp_t *dhcp); + +#endif /* LOGWRITER_H_ */ diff --git a/src/customdhcpcd/signal.c b/src/customdhcpcd/signal.c new file mode 100644 index 0000000..9055c9f --- /dev/null +++ b/src/customdhcpcd/signal.c @@ -0,0 +1,183 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "logger.h" +#include "signal.h" + +static int signal_pipe[2]; +static int signals[5]; + +static const int handle_sigs[] = { + SIGHUP, + SIGALRM, + SIGTERM, + SIGINT +}; + +static void signal_handler (int sig) +{ + unsigned int i = 0; + int serrno = errno; + + /* Add a signal to our stack */ + while (signals[i]) + i++; + if (i > sizeof (signals) / sizeof (signals[0])) + logger (LOG_ERR, "signal buffer overrun"); + else + signals[i] = sig; + + if (write (signal_pipe[1], &sig, sizeof (sig)) == -1) + logger (LOG_ERR, "Could not send signal: %s", strerror (errno)); + + /* Restore errno */ + errno = serrno; +} + +int signal_fd (void) +{ + return (signal_pipe[0]); +} + +/* Check if we have a signal or not */ +int signal_exists (const struct pollfd *fd) +{ + if (signals[0] || (fd && fd->revents & POLLIN)) + return (0); + return (-1); +} + +/* Read a signal from the signal pipe. Returns 0 if there is + * no signal, -1 on error (and sets errno appropriately), and + * your signal on success */ +int signal_read (struct pollfd *fd) +{ + int sig = -1; + + /* Pop a signal off the our stack */ + if (signals[0]) { + unsigned int i = 0; + sig = signals[0]; + while (i < (sizeof (signals) / sizeof (signals[0])) - 1) { + signals[i] = signals[i + 1]; + if (! signals[++i]) + break; + } + } + + if (fd && fd->revents & POLLIN) { + char buf[16]; + size_t bytes; + + memset (buf, 0, sizeof (buf)); + bytes = read (signal_pipe[0], buf, sizeof (buf)); + + if (bytes >= sizeof (sig)) + memcpy (&sig, buf, sizeof (sig)); + + /* We need to clear us from rset if nothing left in the buffer + * in case we are called many times */ + if (bytes == sizeof (sig)) + fd->revents = 0; + } + + return (sig); +} + +/* Call this before doing anything else. Sets up the socket pair + * and installs the signal handler */ +int signal_init (void) +{ + struct sigaction sa; + + if (pipe (signal_pipe) == -1) { + logger (LOG_ERR, "pipe: %s", strerror (errno)); + return (-1); + } + + /* Stop any scripts from inheriting us */ + close_on_exec (signal_pipe[0]); + close_on_exec (signal_pipe[1]); + + /* Ignore child signals and don't make zombies. + * Because we do this, we don't need to be in signal_setup */ + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = SIG_DFL; + sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT; + if (sigaction (SIGCHLD, &sa, NULL) == -1) { + logger (LOG_ERR, "sigaction: %s", strerror (errno)); + return (-1); + } + + memset (signals, 0, sizeof (signals)); + return (0); +} + +int signal_setup (void) +{ + unsigned int i; + struct sigaction sa; + + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = signal_handler; + sigemptyset (&sa.sa_mask); + + for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) + if (sigaction (handle_sigs[i], &sa, NULL) == -1) { + logger (LOG_ERR, "sigaction: %s", strerror (errno)); + return (-1); + } + + return (0); +} + +int signal_reset (void) +{ + struct sigaction sa; + unsigned int i; + + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = SIG_DFL; + sigemptyset (&sa.sa_mask); + + for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) + if (sigaction (handle_sigs[i], &sa, NULL) == -1) { + logger (LOG_ERR, "sigaction: %s", strerror (errno)); + return (-1); + } + + return (0); +} diff --git a/src/customdhcpcd/signal.h b/src/customdhcpcd/signal.h new file mode 100644 index 0000000..63a5906 --- /dev/null +++ b/src/customdhcpcd/signal.h @@ -0,0 +1,40 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SIGNAL_H +#define SIGNAL_H + +#include + +int signal_init (void); +int signal_setup (void); +int signal_reset (void); +int signal_fd (void); +int signal_exists (const struct pollfd *fd); +int signal_read (struct pollfd *fd); + +#endif diff --git a/src/customdhcpcd/socket.c b/src/customdhcpcd/socket.c new file mode 100644 index 0000000..58ad6c5 --- /dev/null +++ b/src/customdhcpcd/socket.c @@ -0,0 +1,647 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#define __FAVOR_BSD /* Nasty hack so we can use BSD semantics for UDP */ +#include +#undef __FAVOR_BSD +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BSD) || defined(__FreeBSD_kernel__) +# include +#elif __linux__ +# include +# include +# define bpf_insn sock_filter +#endif + +#include "config.h" +#include "dhcp.h" +#include "interface.h" +#include "logger.h" +#include "socket.h" + +/* A suitably large buffer for all transactions. + * BPF buffer size is set by the kernel, so no define. */ +#ifdef __linux__ +# define BUFFER_LENGTH 4096 +#endif + +/* Broadcast address for IPoIB */ +static const uint8_t ipv4_bcast_addr[] = { + 0x00, 0xff, 0xff, 0xff, + 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff +}; + +/* Credit where credit is due :) + * The below BPF filter is taken from ISC DHCP */ +static struct bpf_insn dhcp_bpf_filter [] = { + /* Make sure this is an IP packet... */ + BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), + + /* Make sure it's a UDP packet... */ + BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), + + /* Make sure this isn't a fragment... */ + BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), + BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), + + /* Get the IP header length... */ + BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), + + /* Make sure it's to the right port... */ + BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1), + + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT (BPF_RET + BPF_K, ~0U), + + /* Otherwise, drop it. */ + BPF_STMT (BPF_RET + BPF_K, 0), +}; + +static struct bpf_insn arp_bpf_filter [] = { + /* Make sure this is an ARP packet... */ + BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3), + + /* Make sure this is an ARP REPLY... */ + BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), + + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT (BPF_RET + BPF_K, ~0U), + + /* Otherwise, drop it. */ + BPF_STMT (BPF_RET + BPF_K, 0), +}; + +void setup_packet_filters (void) +{ +#ifdef __linux__ + /* We need to massage the filters for Linux cooked packets */ + dhcp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ + dhcp_bpf_filter[2].k -= ETH_HLEN; + dhcp_bpf_filter[4].k -= ETH_HLEN; + dhcp_bpf_filter[6].k -= ETH_HLEN; + dhcp_bpf_filter[7].k -= ETH_HLEN; + + arp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ + arp_bpf_filter[2].k -= ETH_HLEN; +#endif +} + +static uint16_t checksum (unsigned char *addr, uint16_t len) +{ + uint32_t sum = 0; + union + { + unsigned char *addr; + uint16_t *i; + } p; + uint16_t nleft = len; + + p.addr = addr; + while (nleft > 1) { + sum += *p.i++; + nleft -= 2; + } + + if (nleft == 1) { + uint8_t a = 0; + memcpy (&a, p.i, 1); + sum += ntohs (a) << 8; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + + return ~sum; +} + +void make_dhcp_packet(struct udp_dhcp_packet *packet, + const unsigned char *data, size_t length, + struct in_addr source, struct in_addr dest) +{ + struct ip *ip = &packet->ip; + struct udphdr *udp = &packet->udp; + + /* OK, this is important :) + * We copy the data to our packet and then create a small part of the + * ip structure and an invalid ip_len (basically udp length). + * We then fill the udp structure and put the checksum + * of the whole packet into the udp checksum. + * Finally we complete the ip structure and ip checksum. + * If we don't do the ordering like so then the udp checksum will be + * broken, so find another way of doing it! */ + + memcpy (&packet->dhcp, data, length); + + ip->ip_p = IPPROTO_UDP; + ip->ip_src.s_addr = source.s_addr; + if (dest.s_addr == 0) + ip->ip_dst.s_addr = INADDR_BROADCAST; + else + ip->ip_dst.s_addr = dest.s_addr; + + udp->uh_sport = htons (DHCP_CLIENT_PORT); + udp->uh_dport = htons (DHCP_SERVER_PORT); + udp->uh_ulen = htons (sizeof (*udp) + length); + ip->ip_len = udp->uh_ulen; + udp->uh_sum = checksum ((unsigned char *) packet, sizeof (*packet)); + + ip->ip_v = IPVERSION; + ip->ip_hl = 5; + ip->ip_id = 0; + ip->ip_tos = IPTOS_LOWDELAY; + ip->ip_len = htons (sizeof (*ip) + sizeof (*udp) + length); + ip->ip_id = 0; + ip->ip_off = htons (IP_DF); /* Don't fragment */ + ip->ip_ttl = IPDEFTTL; + + ip->ip_sum = checksum ((unsigned char *) ip, sizeof (*ip)); +} + +static int valid_dhcp_packet (unsigned char *data) +{ + union + { + unsigned char *data; + struct udp_dhcp_packet *packet; + } d; + uint16_t bytes; + uint16_t ipsum; + uint16_t iplen; + uint16_t udpsum; + struct in_addr source; + struct in_addr dest; + int retval = 0; + + d.data = data; + bytes = ntohs (d.packet->ip.ip_len); + ipsum = d.packet->ip.ip_sum; + iplen = d.packet->ip.ip_len; + udpsum = d.packet->udp.uh_sum; + + d.data = data; + d.packet->ip.ip_sum = 0; + if (ipsum != checksum ((unsigned char *) &d.packet->ip, + sizeof (d.packet->ip))) + { + logger (LOG_DEBUG, "bad IP header checksum, ignoring"); + retval = -1; + goto eexit; + } + + memcpy (&source, &d.packet->ip.ip_src, sizeof (d.packet->ip.ip_src)); + memcpy (&dest, &d.packet->ip.ip_dst, sizeof (d.packet->ip.ip_dst)); + memset (&d.packet->ip, 0, sizeof (d.packet->ip)); + d.packet->udp.uh_sum = 0; + + d.packet->ip.ip_p = IPPROTO_UDP; + memcpy (&d.packet->ip.ip_src, &source, sizeof (d.packet->ip.ip_src)); + memcpy (&d.packet->ip.ip_dst, &dest, sizeof (d.packet->ip.ip_dst)); + d.packet->ip.ip_len = d.packet->udp.uh_ulen; + if (udpsum && udpsum != checksum (d.data, bytes)) { + logger (LOG_ERR, "bad UDP checksum, ignoring"); + retval = -1; + } + +eexit: + d.packet->ip.ip_sum = ipsum; + d.packet->ip.ip_len = iplen; + d.packet->udp.uh_sum = udpsum; + + return retval; +} + +#if defined(BSD) || defined(__FreeBSD_kernel__) +int open_socket (interface_t *iface, int protocol) +{ + int n = 0; + int fd = -1; + char *device; + int flags; + struct ifreq ifr; + int buf = 0; + struct bpf_program pf; + + device = xmalloc (sizeof (char) * PATH_MAX); + do { + snprintf (device, PATH_MAX, "/dev/bpf%d", n++); + fd = open (device, O_RDWR); + } while (fd == -1 && errno == EBUSY); + free (device); + + if (fd == -1) { + logger (LOG_ERR, "unable to open a BPF device"); + return -1; + } + + close_on_exec (fd); + + memset (&ifr, 0, sizeof (ifr)); + strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); + if (ioctl (fd, BIOCSETIF, &ifr) == -1) { + logger (LOG_ERR, + "cannot attach interface `%s' to bpf device `%s': %s", + iface->name, device, strerror (errno)); + close (fd); + return -1; + } + + /* Get the required BPF buffer length from the kernel. */ + if (ioctl (fd, BIOCGBLEN, &buf) == -1) { + logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno)); + close (fd); + return -1; + } + iface->buffer_length = buf; + + flags = 1; + if (ioctl (fd, BIOCIMMEDIATE, &flags) == -1) { + logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno)); + close (fd); + return -1; + } + + /* Install the DHCP filter */ + if (protocol == ETHERTYPE_ARP) { + pf.bf_insns = arp_bpf_filter; + pf.bf_len = sizeof (arp_bpf_filter) + / sizeof (arp_bpf_filter[0]); + } else { + pf.bf_insns = dhcp_bpf_filter; + pf.bf_len = sizeof (dhcp_bpf_filter) + / sizeof (dhcp_bpf_filter[0]); + } + if (ioctl (fd, BIOCSETF, &pf) == -1) { + logger (LOG_ERR, "ioctl BIOCSETF: %s", strerror (errno)); + close (fd); + return -1; + } + + if (iface->fd > -1) + close (iface->fd); + iface->fd = fd; + + return fd; +} + +ssize_t send_packet (const interface_t *iface, int type, + const unsigned char *data, size_t len) +{ + ssize_t retval = -1; + struct iovec iov[2]; + + if (iface->family == ARPHRD_ETHER) { + struct ether_header hw; + memset (&hw, 0, sizeof (hw)); + memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); + hw.ether_type = htons (type); + + iov[0].iov_base = &hw; + iov[0].iov_len = sizeof (hw); + } else { + logger (LOG_ERR, "unsupported interace type %d", iface->family); + return -1; + } + iov[1].iov_base = (unsigned char *) data; + iov[1].iov_len = len; + + if ((retval = writev(iface->fd, iov, 2)) == -1) + logger (LOG_ERR, "writev: %s", strerror (errno)); + + return retval; +} + +/* BPF requires that we read the entire buffer. + * So we pass the buffer in the API so we can loop on >1 dhcp packet. */ +ssize_t get_packet (const interface_t *iface, unsigned char *data, + unsigned char *buffer, + size_t *buffer_len, size_t *buffer_pos) +{ + union + { + unsigned char *buffer; + struct bpf_hdr *packet; + } bpf; + + bpf.buffer = buffer; + + if (*buffer_pos < 1) { + memset (bpf.buffer, 0, iface->buffer_length); + *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length); + *buffer_pos = 0; + if (*buffer_len < 1) { + struct timespec ts; + logger (LOG_ERR, "read: %s", strerror (errno)); + ts.tv_sec = 3; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); + return (-1); + } + } else + bpf.buffer += *buffer_pos; + + while (bpf.packet) { + size_t len = 0; + union + { + unsigned char *buffer; + struct ether_header *hw; + } hdr; + unsigned char *payload; + bool have_data = false; + + /* Ensure that the entire packet is in our buffer */ + if (*buffer_pos + bpf.packet->bh_hdrlen + bpf.packet->bh_caplen + > (unsigned) *buffer_len) + break; + + hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen; + payload = hdr.buffer + sizeof (*hdr.hw); + + /* If it's an ARP reply, then just send it back */ + if (hdr.hw->ether_type == htons (ETHERTYPE_ARP)) { + len = bpf.packet->bh_caplen - + sizeof (*hdr.hw); + memcpy (data, payload, len); + have_data = true; + } else { + if (valid_dhcp_packet (payload) >= 0) { + union + { + unsigned char *buffer; + struct udp_dhcp_packet *packet; + } pay; + pay.buffer = payload; + len = ntohs (pay.packet->ip.ip_len) - + sizeof (pay.packet->ip) - + sizeof (pay.packet->udp); + memcpy (data, &pay.packet->dhcp, len); + have_data = true; + } + } + + /* Update the buffer_pos pointer */ + bpf.buffer += BPF_WORDALIGN (bpf.packet->bh_hdrlen + + bpf.packet->bh_caplen); + if ((unsigned) (bpf.buffer - buffer) < *buffer_len) + *buffer_pos = bpf.buffer - buffer; + else + *buffer_pos = 0; + + if (have_data) + return len; + + if (*buffer_pos == 0) + break; + } + + /* No valid packets left, so return */ + *buffer_pos = 0; + return -1; +} + +#elif __linux__ + +int open_socket (interface_t *iface, int protocol) +{ + int fd; + union sockunion { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_ll sll; + struct sockaddr_storage ss; + } su; + struct sock_fprog pf; + struct ifreq ifr; + int n = 1; + + /* We need to bind to a port, otherwise Linux generate ICMP messages + * that cannot contect the port when we have an address. + * We don't actually use this fd at all, instead using our packet + * filter socket. */ + if (iface->listen_fd == -1 && protocol == ETHERTYPE_IP) { + if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + } else { + memset (&su, 0, sizeof (su)); + su.sin.sin_family = AF_INET; + su.sin.sin_port = htons (DHCP_CLIENT_PORT); + if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, + &n, sizeof (n)) == -1) + logger (LOG_ERR, "SO_REUSEADDR: %s", + strerror (errno)); + if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, + &n, sizeof (n)) == -1) + logger (LOG_ERR, "SO_RCVBUF: %s", + strerror (errno)); + memset (&ifr, 0, sizeof (ifr)); + strncpy (ifr.ifr_name, iface->name, + sizeof (ifr.ifr_name)); + if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, + &ifr, sizeof (ifr)) == -1) + logger (LOG_ERR, "SO_SOBINDTODEVICE: %s", + strerror (errno)); + if (bind (fd, &su.sa, sizeof (su)) == -1) { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (fd); + } else { + iface->listen_fd = fd; + close_on_exec (fd); + } + } + } + + if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (protocol))) == -1) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + close_on_exec (fd); + + memset (&su, 0, sizeof (su)); + su.sll.sll_family = PF_PACKET; + su.sll.sll_protocol = htons (protocol); + if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) { + logger (LOG_ERR, + "if_nametoindex: no index for interface `%s'", + iface->name); + close (fd); + return (-1); + } + + /* Install the DHCP filter */ + memset (&pf, 0, sizeof (pf)); + if (protocol == ETHERTYPE_ARP) { + pf.filter = arp_bpf_filter; + pf.len = sizeof (arp_bpf_filter) / sizeof (arp_bpf_filter[0]); + } else { + pf.filter = dhcp_bpf_filter; + pf.len = sizeof (dhcp_bpf_filter) / sizeof (dhcp_bpf_filter[0]); + } + if (setsockopt (fd, SOL_SOCKET, SO_ATTACH_FILTER, + &pf, sizeof (pf)) != 0) + { + logger (LOG_ERR, "SO_ATTACH_FILTER: %s", strerror (errno)); + close (fd); + return (-1); + } + + if (bind (fd, &su.sa, sizeof (su)) == -1) { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (fd); + return (-1); + } + + if (iface->fd > -1) + close (iface->fd); + iface->fd = fd; + iface->socket_protocol = protocol; + iface->buffer_length = BUFFER_LENGTH; + + return (fd); +} + +ssize_t send_packet (const interface_t *iface, int type, + const unsigned char *data, size_t len) +{ + union sockunion { + struct sockaddr sa; + struct sockaddr_ll sll; + struct sockaddr_storage ss; + } su; + ssize_t retval; + + if (! iface) + return (-1); + + memset (&su, 0, sizeof (su)); + su.sll.sll_family = AF_PACKET; + su.sll.sll_protocol = htons (type); + + if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) { + logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", + iface->name); + return (-1); + } + + su.sll.sll_hatype = htons (iface->family); + su.sll.sll_halen = iface->hwlen; + if (iface->family == ARPHRD_INFINIBAND) + memcpy (&su.sll.sll_addr, + &ipv4_bcast_addr, sizeof (ipv4_bcast_addr)); + else + memset (&su.sll.sll_addr, 0xff, iface->hwlen); + + if ((retval = sendto (iface->fd, data, len, 0, &su.sa, + sizeof (su))) == -1) + + logger (LOG_ERR, "sendto: %s", strerror (errno)); + return (retval); +} + +/* Linux has no need for the buffer as we can read as much as we want. + * We only have the buffer listed to keep the same API. */ +ssize_t get_packet (const interface_t *iface, unsigned char *data, + unsigned char *buffer, + size_t *buffer_len, size_t *buffer_pos) +{ + ssize_t bytes; + union + { + unsigned char *buffer; + struct udp_dhcp_packet *packet; + } pay; + + /* We don't use the given buffer, but we need to rewind the position */ + *buffer_pos = 0; + + memset (buffer, 0, iface->buffer_length); + bytes = read (iface->fd, buffer, iface->buffer_length); + + if (bytes == -1) { + struct timespec ts; + logger (LOG_ERR, "read: %s", strerror (errno)); + ts.tv_sec = 3; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); + return (-1); + } + + *buffer_len = bytes; + /* If it's an ARP reply, then just send it back */ + if (iface->socket_protocol == ETHERTYPE_ARP) { + memcpy (data, buffer, bytes); + return (bytes); + } + + if ((unsigned) bytes < (sizeof (pay.packet->ip) + + sizeof (pay.packet->udp))) + { + logger (LOG_DEBUG, "message too short, ignoring"); + return (-1); + } + + pay.buffer = buffer; + if (bytes < ntohs (pay.packet->ip.ip_len)) { + logger (LOG_DEBUG, "truncated packet, ignoring"); + return (-1); + } + + if (valid_dhcp_packet (buffer) == -1) + return (-1); + + bytes = ntohs (pay.packet->ip.ip_len) - + (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)); + memcpy (data, &pay.packet->dhcp, bytes); + return (bytes); +} + +#else + #error "Platform not supported!" + #error "We currently support BPF and Linux sockets." + #error "Other platforms may work using BPF. If yours does, please let me know" + #error "so I can add it to our list." +#endif diff --git a/src/customdhcpcd/socket.h b/src/customdhcpcd/socket.h new file mode 100644 index 0000000..bdf26d0 --- /dev/null +++ b/src/customdhcpcd/socket.h @@ -0,0 +1,46 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright 2006-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SOCKET_H +#define SOCKET_H + +#include + +#include "dhcp.h" +#include "interface.h" + +void setup_packet_filters (void); +void make_dhcp_packet(struct udp_dhcp_packet *packet, + const unsigned char *data, size_t length, + struct in_addr source, struct in_addr dest); + +int open_socket (interface_t *iface, int protocol); +ssize_t send_packet (const interface_t *iface, int type, + const unsigned char *data, size_t len); +ssize_t get_packet (const interface_t *iface, unsigned char *data, + unsigned char *buffer, size_t *buffer_len, size_t *buffer_pos); +#endif diff --git a/src/customdhcpcd/version.h b/src/customdhcpcd/version.h new file mode 100644 index 0000000..9cf5fa4 --- /dev/null +++ b/src/customdhcpcd/version.h @@ -0,0 +1 @@ +#define VERSION "3.2.3" diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp deleted file mode 100644 index 653bc7b..0000000 --- a/src/downloadmanager.cpp +++ /dev/null @@ -1,215 +0,0 @@ -#include "downloadmanager.h" - -// static counter to save the number of successfully downloaded files. -int DownloadManager::_downloaded = 0; -// ------------------------------------------------------------------------------------------------------- -// Initialisation -// ------------------------------------------------------------------------------------------------------- -// Constructor initialises a QNetworkAccessManager needed to create/received download requests/replies -// This object is then moved to the thread for the download manager, to ensure that downloads -// are done in a separate thread (to avoid GUI blocking.) -// The flag "_dip" starts as false, since no download is in progress. -// This flag is needed to control queueing functionality. -// Lastly the given download directory's existance is checked. (see below) - -DownloadManager::DownloadManager() { - qxtLog->debug() << "Initializing download manager..."; - checkDownloadDirectory(); - _qnam = new QNetworkAccessManager(); - _qnam->moveToThread(&dmThread); - _dip = false; -} -// Destructor -DownloadManager::~DownloadManager() { - delete _qnam; -} -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::checkDownloadDirectory() { - // check if downloadPath exists, if not create it. - _downloadDir = QDir(downloadPath); - if (!_downloadDir.exists()) { - qxtLog->debug() << "[dm] Download directory: " << _downloadDir.path() << " doesn't exist."; - // try to create the directory - if (QDir::current().mkdir(downloadPath)) - qxtLog->debug() << "[dm] Created download directory: " << _downloadDir.path(); - else { - qxtLog->debug() << "[dm] Failed to create directory: " << _downloadDir.path(); - // try to save to /tmp/fbgui - _downloadDir.setPath(QDir::tempPath() + "/fbgui"); - if (!_downloadDir.exists()) { - if (QDir::current().mkdir(QDir::tempPath() + "/fbgui")) - qxtLog->debug() << "[dm] Successfully created: " << _downloadDir.absolutePath(); - else { - // just in case - qxtLog->debug() << "[dm] Failed to create: " << _downloadDir.absolutePath(); - qxtLog->debug() << "[dm] Exiting..."; - exit( EXIT_FAILURE); - } - } else - qxtLog->debug() << "[dm] " << _downloadDir.absolutePath() << " already exists."; - } - } else - qxtLog->debug() << "[dm] Download directory: " << _downloadDir.absolutePath() - << " already exists."; - - qxtLog->debug() << "[dm] Saving downloads to: " << _downloadDir.absolutePath(); - downloadPath = _downloadDir.absolutePath(); -} -// ------------------------------------------------------------------------------------------------------- -// Public access -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::downloadFile(const QString& filename) { - QUrl fileUrl(baseURL.resolved(QUrl(filename))); - this->processDownloadRequest(fileUrl); -} -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::downloadFile(const QUrl& fileUrl) { - this->processDownloadRequest(fileUrl); -} -// ------------------------------------------------------------------------------------------------------- -// Private functions handling download requests and queueing -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::processDownloadRequest(const QUrl& url) { - if (url.isEmpty()) { - qxtLog->debug() << "[dm] No URL specified for download."; - return; - } - qxtLog->debug() << "[dm] Enqueueing: " << url.toString(); - _downloadQueue.enqueue(url); - if (_dip) { - // download in progress, return. - qxtLog->debug() << "[dm] Download in progress! Queued:" << url.toString() << "(" - << _downloadQueue.size() << " in queue)"; - return; - } - // no running downloads: start next in queue - startNextDownload(); -} -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::startNextDownload() { - //QWSServer::instance()->setCursorVisible(false); - if (_downloadQueue.isEmpty()) { - emit downloadQueueEmpty(); - qxtLog->debug() << "[dm] Download manager ready. (1)"; - return; - } - qxtLog->debug() << "[dm] Starting next download: " << _downloadQueue.head().toString() << " (" - << _downloadQueue.size() - 1 << " in queue.)"; - - // dequeue next URL to download. - QUrl url = _downloadQueue.dequeue(); - - // get filename from URL. - QString tmp = url.path(); - tmp.remove(0, tmp.lastIndexOf(QChar('/')) + 1); - - // check if filename exists on target file system - if (_downloadDir.exists(tmp)) { - qxtLog->debug() << "[dm] File already exists: " << _downloadDir.absoluteFilePath(tmp); - _outfile.setFileName( - QString(_downloadDir.absolutePath() + "/" + tmp + ".\%1").arg(_downloaded)); - } else - _outfile.setFileName(_downloadDir.absoluteFilePath(tmp)); - qxtLog->debug() << "[dm] Saving to: " << _outfile.fileName(); - - // try to open for writing - if (!_outfile.open(QIODevice::WriteOnly)) { - qxtLog->debug() << "[dm] No write access to " << _outfile.fileName() - << " . Skipping download..."; - return; - } - - // send the request for the file - QNetworkRequest request(url); - _currentDownload = _qnam->get(request); - _lastProgress = 0; - _currentProgress = 0; - _dip = true; - time.start(); - QObject::connect(_currentDownload, SIGNAL(readyRead()), this, SLOT( - downloadReady())); - QObject::connect(_currentDownload, SIGNAL(metaDataChanged()), this, SLOT( - processMetaInfo())); - QObject::connect(_currentDownload, SIGNAL(downloadProgress(qint64, qint64)), this, - SLOT(downloadProgress(qint64, qint64))); - QObject::connect(_currentDownload, SIGNAL(finished()), this, SLOT( - downloadFinished())); -} -// ------------------------------------------------------------------------------------------------------- -// Private slots to handle a download in progress -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::processMetaInfo() { - // fetch filesize from header & filename from URL (for now) - const QByteArray cltag = "Content-Length"; - QByteArray clinfo = _currentDownload->rawHeader(cltag); - QFileInfo fi(_outfile); - qxtLog->debug() << "[dm] Download Info: " << fi.fileName() << " (Size: " << clinfo.toDouble() - << ")"; - emit downloadInfo(fi.fileName(), clinfo.toDouble()); -} -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::downloadReady() { - // data ready, save it - _outfile.write(_currentDownload->readAll()); -} -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::downloadProgress(qint64 bytesIn, qint64 bytesTotal) { - if (bytesIn > bytesTotal || bytesTotal <= 0) { - qxtLog->debug() << "[dm] downloadProgress invalid values:" << "In:" << bytesIn - << " / Total: " << bytesTotal; - return; - } - // calculate current speed - double speed = bytesIn * 1000 / time.elapsed(); - QString unit; - if (speed < 1024) { - unit = "bytes/sec"; - } else if (speed < 1024 * 1024) { - speed /= 1024; - unit = "KB/s"; - } else { - speed /= 1024 * 1024; - unit = "MB/s"; - } - // update progress only if difference higher than the updateInterval setting - _currentProgress = ((bytesIn * 100) / bytesTotal); - if (_currentProgress - _lastProgress >= updateInterval) { - _lastProgress = _currentProgress; - emit - updateProgress(_currentProgress, speed, unit); - qxtLog->debug() << "[dm] Download progress of " << _currentDownload->url().toString() << ": " - << bytesIn << "/" << bytesTotal << "(" << _currentProgress << "\%)"; - } -} -// ------------------------------------------------------------------------------------------------------- -void DownloadManager::downloadFinished() { - // check for errors - if (_currentDownload->error()) { - _outfile.close(); - _outfile.remove(); - int statusCode = - _currentDownload->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - qxtLog->debug() << "[dm] Download of " << _currentDownload->url().toString() - << " failed with HTTP error code: " << statusCode; - emit - notify(QString("Download failed! HTTP Status Code: %1").arg(statusCode)); - _currentDownload->deleteLater(); - } else { - // end download - _outfile.close(); - _downloaded++; - qxtLog->debug() << "[dm] Download of " << _currentDownload->url().toString() - << " finished. (downloaded = " << _downloaded << ")"; - emit - notify(QString("Successfully downloaded %1").arg(_currentDownload->url().toString())); - _currentDownload->deleteLater(); - } - _dip = false; - // process next in queue, if any - if (_downloadQueue.isEmpty()) { - emit downloadQueueEmpty(); - qxtLog->debug() << "[dm] Download manager ready. (2)"; - return; - } - startNextDownload(); -} diff --git a/src/downloadmanager.h b/src/downloadmanager.h deleted file mode 100644 index 62df4bc..0000000 --- a/src/downloadmanager.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - * - * - * Class managing download requests: - * - provides queueing functionality - * - static info: filename, filesize - * - dynamic info: download progress, current speed - * - */ - -#ifndef DOWNLOADMANAGER_H -#define DOWNLOADMANAGER_H - -#include "fbgui.h" - -extern bool debug; -extern QUrl baseURL; -extern QString binPath; -extern QString downloadPath; -extern int updateInterval; - -class DownloadManager: public QObject { -Q_OBJECT - -public: - DownloadManager(); - ~DownloadManager(); - QTime time; - -private: - // checks for valid download directory, ran once in constructor - void checkDownloadDirectory(); - // private control function for queueing mechanism. - void processDownloadRequest(const QUrl& url); - - // base objects for downloading - QNetworkAccessManager* _qnam; - QQueue _downloadQueue; - QNetworkReply* _currentDownload; - QFile _outfile; - QDir _downloadDir; - // download progress variables - int _currentProgress, _lastProgress; - // download in progress flag - bool _dip; - // static counter - static int _downloaded; - -signals: - // notify sends a message to the javascript interface to be evaluated there - void notify(const QString& msg); - // downloadInfo sends static information (name, size) to the interface. - void downloadInfo(const QString& filename, const double& filesize); - // updateProgress sends download progress information to the interface. - void updateProgress(const int& percent, const double& speed, const QString& unit); - // signal emitted when download queue is empty. - void downloadQueueEmpty(); - -public slots: - // public slots to receive download requests. - void downloadFile(const QUrl& fileUrl); - // convenience function - void downloadFile(const QString& fileUrl); - -private slots: - // private slots to manage the downloading process - void startNextDownload(); - void processMetaInfo(); - void downloadReady(); - void downloadProgress(qint64 bytesIn, qint64 bytesTotal); - void downloadFinished(); -}; - -#endif // DOWNLOADMANAGER_H diff --git a/src/fbgui.cpp b/src/fbgui.cpp deleted file mode 100644 index 22a2ac6..0000000 --- a/src/fbgui.cpp +++ /dev/null @@ -1,492 +0,0 @@ -#include "fbgui.h" -#include "sysinfo.h" -#include "loggerengine.h" -#include "downloadmanager.h" -#include "javascriptinterface.h" - -#include -#include -#include -#include - -QThread dmThread; -QString logFilePath(""); -QString ipConfigFilePath(""); -QString binPath(""); -QUrl baseURL(""); -QString downloadPath(""); -int updateInterval = -1; -QString fileToTriggerURL(""); -QString serialLocation(""); -QString sessionID(""); -int debugMode = -1; - -//------------------------------------------------------------------------------------------- -/** - * A constructor. - * - * The constructor of the fbgui class. It initializes the main objects - * which are needed while the program is running. - * The appearance of the webView is here also defined. - * - * @see JavascriptInterface - * @see DownloadManager - */ -fbgui::fbgui() { -} -fbgui::~fbgui() { - dmThread.quit(); -} - - - -/** - * init function. - */ -void fbgui::init() { - // start fbgui - qxtLog->debug() << "Initializing fbgui..."; - - setupLayout(); - createActions(); - - // initialize javascript interface - JavascriptInterface* jsi = new JavascriptInterface( - _webView->page()->mainFrame()); - QObject::connect(jsi, SIGNAL(quitFbgui()), this, SLOT(close())); - QObject::connect(jsi, SIGNAL(shutDownClient()), this, - SLOT(performShutDown())); - QObject::connect(_webView->page()->mainFrame(), SIGNAL( - javaScriptWindowObjectCleared()), jsi, SLOT(attachToDOM())); - - // initialize download manager - DownloadManager* dm = new DownloadManager(); - QObject::connect(dm, SIGNAL(downloadInfo(const QString&, const double&)), - jsi, SLOT(downloadInfo(const QString&, const double&))); - QObject::connect(dm, SIGNAL(notify(const QString&)), jsi, - SLOT(notify(const QString&))); - QObject::connect(jsi, SIGNAL(requestFile(const QString&)), dm, - SLOT(downloadFile(const QString&))); - QObject::connect( - dm, - SIGNAL(updateProgress(const int&, const double&, const QString&)), - jsi, - SLOT(updateProgressBar(const int&, const double&, const QString&))); - QObject::connect(dm, SIGNAL(downloadQueueEmpty()), jsi, SLOT( - callbackOnFinished())); - QObject::connect(dm, SIGNAL(downloadQueueEmpty()), this, SLOT(loadSystem())); - - // move download manager to its own thread - dm->moveToThread(&dmThread); - dmThread.start(); - - // show "waiting for internet" page until triggered. - if (debugMode > -1) { - _webView->load(QUrl("qrc:/html/preload-debug.html")); - } else { - _webView->load(QUrl("qrc:/html/preload.html")); - } - - // watcher is not needed anymore since we guarantee internet connection with the networkDiscovery. - // start watching for fileToTriggerURL - //watchForTrigger(); - loadURL(); - - // set properties - setWindowTitle("fbgui"); - setAttribute(Qt::WA_QuitOnClose, true); - setWindowFlags(Qt::FramelessWindowHint); - showFullScreen(); - this->show(); -} -//------------------------------------------------------------------------------------------- -// Layout / actions setup -//------------------------------------------------------------------------------------------- -/** - * This method sets the used Layout. - * - * This method sets the used Layout. Possible layout are: - * - browser mode: only the browser is visible - * - debug mode: the screen is divided into the browser and a debug - * out console - */ -void fbgui::setupLayout() { - // setup layout of the gui: debug split or browser - _webView = new QWebView(this); - if (debugMode == 1) { - // split main window in browser & debug console - createDebugConsole(); - _splitter = new QSplitter(Qt::Vertical, this); - _splitter->addWidget(_webView); - _splitter->addWidget(_debugConsole); - setCentralWidget(_splitter); - } else - setCentralWidget(_webView); -} -//------------------------------------------------------------------------------------------- -/** - * This method enables a shortcut for closing the program. - * The shortcut itself is not configurable: CTRL + X - */ -void fbgui::createActions() { - _quit = new QAction(tr("&quit"), this); - _quit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X)); - this->addAction(_quit); - connect(_quit, SIGNAL(triggered()), this, SLOT(close())); -} -//------------------------------------------------------------------------------------------- -// File system watching -//------------------------------------------------------------------------------------------- -/** - * This method sets a "watchdog" to a special file. - * - * This method sets a "watchdog" to a special file. If needed it creates the - * file which it has to watch over. It than connects a QFileSystemWatcher with - * this file. If changes happen to this file, the - * fbgui::checkForTrigger(const QString& dirname) method will be called. - * - */ -void fbgui::watchForTrigger() { - // check if fileToTriggerURL already exists - QFile file(fileToTriggerURL); - if (file.exists()) { - qxtLog->debug() << "[watcher] " << fileToTriggerURL << " found."; - // try to load URL - loadURL(); - } else { - // create it - if (file.open(QIODevice::WriteOnly)) { - qxtLog->debug() << "[gui] Created: " << fileToTriggerURL; - file.close(); - } else { - qxtLog->debug() << "[gui] Creation of " << fileToTriggerURL - << " failed!"; - qxtLog->debug() << "[gui] Exiting in 5 seconds..."; - QTimer::singleShot(5000, this, SLOT(close())); - } - } - // watch the path to trigger file - qxtLog->debug() << "[watcher] Watching " << fileToTriggerURL; - _watcher = new QFileSystemWatcher(QStringList(fileToTriggerURL), this); -QObject::connect(_watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(prepareURLLoad())); - -} -//------------------------------------------------------------------------------------------- -/** - * This method checks if the trigger was valid. - * - * This method checks if the trigger was valid. If yes, - * we have received an IP Address an can load the main screen. - * If not, something some error happened. - * - * @see fbgui::checkHost() - * @see fbgui::loadURL() - */ -void fbgui::prepareURLLoad() { - qxtLog->debug() << "[watcher] " << fileToTriggerURL << " changed!"; - // disconnect _watcher, his job is done - qxtLog->debug() << "[watcher] disconnected."; - _watcher->disconnect(this); - _watcher->deleteLater(); - // try to load URL - loadURL(); -} -//------------------------------------------------------------------------------------------- -// Preparations for URL load -//------------------------------------------------------------------------------------------- -/** - * This method checks the existance of the host. - * - * This method checks if the host exists / can be found. - * The host is from the URL given through the configuration. - */ -bool fbgui::checkHost() const { - QHostInfo hostInfo = QHostInfo::fromName(baseURL.host()); - if (hostInfo.error() != QHostInfo::NoError) { - qxtLog->debug() << "[gui] Lookup of " << baseURL.host() << "failed."; - qxtLog->debug() << "[gui] Host can not be reached."; - return false; - } else { - qxtLog->debug() << "[gui] Lookup of " << baseURL.host() << " succeeded."; - return true; - } -} -//------------------------------------------------------------------------------------------- -/** - * This method tries loads the URL. - * - * This method loads the main screen via an POST request. If also disconnects the watcher - * of the file, (Watcher is set in the fbgui::watchForTrigger() method). - * and generates the POST data body. - * - * @see fbgui::watchForTrigger() - * @see fbgui::generatePOSTData() - */ -void fbgui::loadURL() { - if (checkHost()) { - qxtLog->debug() << "[gui] Loading URL: " << baseURL.toString() << " ..."; - - // Generate POST identification data needed by PBS. - QByteArray postData = generatePOSTData(); - QNetworkRequest req(baseURL); - - // show cursor again since user is about to interact. - //QWSServer::instance()->setCursorVisible(true); - QObject::connect(_webView, SIGNAL(loadFinished(bool)), this, SLOT(loadURLDone(bool))); - _webView->load(req, QNetworkAccessManager::PostOperation, postData); - } - // TODO: error page if no host. -} -void fbgui::loadURLDone(bool success) { - // done contains the success of the loading: false / true - if (!success) { - qxtLog->debug() << "[gui] Loading failed. URL: " - << _webView->url().toString(); - qxtLog->debug() << "[gui] You can quit with CTRL + X ..."; - // TODO handle failure properly... - } else { - qxtLog->debug() << "[gui] Loaded URL: " << _webView->url().toString(); - } -} -//------------------------------------------------------------------------------------------- -/** - * This method generates the POST data body. - * - * This method generates the POST data body. The body contains the - * MAC address, an hardwarehash and a specific serial number. - * The hardwarehash is a MD5 hash over the MAC address and the - * mainboard serial number. - * The specific serial number is set at the creation of the usb boot stick. - * This file has to be present on the directory specified in - * the configuration for this to work. - * - * @see SysInfo::getMACAddress() - * @see SysInfo::getMainboardSerial() - */ -QByteArray fbgui::generatePOSTData() { - qxtLog->debug() << "[gui] Generating POST data..."; - // use MAC address as base data - SysInfo si; - QByteArray data(si.getInfo("mac").toUtf8()); - // append mainboard serial to the mac address for more unique hardwarehash - QByteArray mbserial(si.getInfo("mbserial").toUtf8()); - if (!mbserial.isEmpty()) - data.append(mbserial); - else { - qxtLog->debug() - << "[gui] Mainboard serial was empty. Not appending to base hash data."; - } - qxtLog->debug() << "[post] Hashing: " << data; - // generate MD5 hash of data - QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); - qxtLog->debug() << "[post] MD5 Hash: " << hash.toHex(); - - // fetch serial number from usb - QByteArray serial; - QFile file(serialLocation); - if (!file.open(QIODevice::ReadOnly)) { - qxtLog->debug() << "[post] No such file: " << file.fileName(); - } - // everything ok, read data - serial = file.readAll(); - file.close(); - serial.chop(1); // chop EOF - qxtLog->debug() << "[post] Serial number is: " << serial; - - // construct final byte array - QByteArray postData("mac="); - postData.append(si.getInfo("mac")); - postData.append("&hardwarehash=" + hash.toHex()); - postData.append("&serialnumber=" + serial); - qxtLog->debug() << "[post] POST data: " << postData; - return postData; -} - -//------------------------------------------------------------------------------------------- -// Shutdown / Reboot of the client -//------------------------------------------------------------------------------------------- -// TODO One function for reboot and shutdown, with parameter for the action. -// for example: doSystemCall(_REBOOT_); -/** - * This method performs the shutdown of the client. - * - * This method performs the shutdown of the client. It is triggered by the - * JavascriptInterface::shutDownClient() signal which will be emited in the - * JavascriptInterface::shutDown() method. - * This method writes the character 'o' in /proc/sysrq-trigger - * which will shutdown the computer immediatly. - * (See linux magic keys) - * - * @see JavascriptInterface::shutDownClient() - * @see JavascriptInterface::shutDown() - */ -void fbgui::performShutDown() { - QFile file("/proc/sysrq-trigger"); - if (file.open(QIODevice::WriteOnly)) { - file.write("o"); - file.close(); - } else { - qxtLog->debug() << "[gui] Could not open /proc/sysrq-trigger"; - } -} -//------------------------------------------------------------------------------------------- -/** - * This method performs the reboot of the client. - * - * This method performs the reboot of the client. It is triggered by the - * JavascriptInterface::rebootClient() signal which will be emited in the - * JavascriptInterface::reboot() method. - * This method writes the character 'b' in /proc/sysrq-trigger - * which will shutdown the computer immediatly. - * (See linux magic keys) - * - * @see JavascriptInterface::rebootClient() - * @see JavascriptInterface::reboot() - */ -void fbgui::performReboot() { - QFile file("/proc/sysrq-trigger"); - if (file.open(QIODevice::WriteOnly)) { - file.write("b"); - file.close(); - } else { - qxtLog->debug() << "[gui] Could not open /proc/sysrq-trigger"; - } -} -//------------------------------------------------------------------------------------------- -// Preparing Kernel Switch per kexec (initiating Stage 3) -//------------------------------------------------------------------------------------------- -void fbgui::loadSystem() { - //show loading system page. - //_webView->disconnect(this); - //QObject::connect(_webView, SIGNAL(loadFinished(bool)), this, SLOT(prepareKexec())); - _webView->load(QUrl("qrc:/html/loadsystem.html")); - QTimer::singleShot(1000, this, SLOT(prepareKexec())); -} -//------------------------------------------------------------------------------------------- -/** - * This method prepares kexec. - * - * The kernel command line file that should have been downloaded from the Preboot-Server - * and the ip config file (created by udhcpc) are merged into the final completed KCL. - * - * A process is then started to load the kernel, initramfs and kcl into kexec. - * The process tries to execute kexec -l with these parameters. - * - * If this succeeds, runKexec() is called - * - * @see fbgui::runKexec() - * - */ -void fbgui::prepareKexec() { - - qxtLog->debug() << "[gui] Preparing kexec ..."; - // try to read KCL file that was downloaded. - QFile file(downloadPath + "/kcl"); - if (!file.open(QIODevice::ReadOnly)) { - qxtLog->debug() << "[gui] No such file: " << file.fileName(); - } - // everything ok, read data. - QString kcl = file.readAll(); - file.close(); - qxtLog->debug() << "[gui] KCL from PBS: " << kcl; - - // try to read ipconfig file generated by udhcpc. - file.setFileName("/tmp/ip_config_fbgui"); - if (!file.open(QIODevice::ReadOnly)) { - qxtLog->debug() << "[gui] No such file: " << file.fileName(); - } - // everything ok, read data. - QString ipConfig = file.readAll(); - file.close(); - qxtLog->debug() << "[gui] IP config: " << ipConfig; - - // append ipConfig - kcl.append(" ip="); - kcl.append(ipConfig); - qxtLog->debug() << "[gui] Complete KCL: " << kcl; - - // load the kernel + initramfs + append of kcl into kexec. - QProcess *process = new QProcess(this); - QString cmdline = "kexec -l " + downloadPath.toUtf8() + "/kernel --initrd=" - + downloadPath.toUtf8() + "/initramfs --append=\"" + kcl.toUtf8() - + "\""; - qxtLog->debug() << "[gui] kexec cmdline: " << cmdline; - process->start(cmdline); - bool ret = process->waitForFinished(); - if (!ret) { - qxtLog->debug() << "[gui] Failed to execute: " << cmdline; - qxtLog->debug() << "[gui] Exiting in 5 seconds..."; - QTimer::singleShot(5000, this, SLOT(close())); - } else { - qxtLog->debug() << "[gui] Kexec load was successfull."; - if (debugMode < 0) { - // if process successfully finished, try to run kexec -e - runKexec(); - } else { - qxtLog->debug() - << "[gui] Skipping execution of kexec - open debug shell."; - qxtLog->debug() - << "[gui] To start the system execute \"kexec -e\" in your shell."; - close(); - } - } -} -//------------------------------------------------------------------------------------------- -/** - * This method tries to execute: kexec -e - * - * This method tries to execute: kexec -e - * - */ -void fbgui::runKexec() { - QProcess *process = new QProcess(this); - process->start("kexec -e"); - if (!process->waitForStarted()) { - qxtLog->debug() << "[gui] Failed to execute: kexec -e"; - qxtLog->debug() << "[gui] Exiting in 5 seconds..."; - QTimer::singleShot(5000, this, SLOT(close())); - //TODO: Handle failure properly... - } -} -//------------------------------------------------------------------------------------------- -// Debug console setup / control -//------------------------------------------------------------------------------------------- -/** - * This method creates a debug console as a widget. - * - * It is basicly a QTextEdit widget as provided by QT's Framework. - * An action to toggle this widget is implemented (CTRL + D). - * - * @see fbgui::toggleDebugConsole() - */ -void fbgui::createDebugConsole() { - // create the debug console widget - _debugConsole = new QTextEdit(this); - _debugConsole->setWindowFlags(Qt::FramelessWindowHint); - // fanciness - QPalette pal; - pal.setColor(QPalette::Base, Qt::black); - _debugConsole->setPalette(pal); - _debugConsole->setTextColor(Qt::white); - // enable custom logger engine - qxtLog->addLoggerEngine("fb_logger", new LoggerEngine_fb(_debugConsole)); - //qxtLog->initLoggerEngine("fb_logger"); - qxtLog->setMinimumLevel("fb_logger", QxtLogger::DebugLevel); - // CTRL + D toggles debug window - _toggleDebugConsole = new QAction(tr("&toggleDebug"), this); - _toggleDebugConsole->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); - addAction(_toggleDebugConsole); - connect(_toggleDebugConsole, SIGNAL(triggered()), this, SLOT( - toggleDebugConsole())); -} -//------------------------------------------------------------------------------------------- -/** - * This method toggles the debug console. - * - * Toggle the visibility of the debug console if the action _toggleDebugConsole is triggered. - * - * @see fbgui::createDebugConsole() - */ -void fbgui::toggleDebugConsole() { - (_debugConsole->isVisible()) ? _debugConsole->hide() : _debugConsole->show(); -} diff --git a/src/fbgui.h b/src/fbgui.h deleted file mode 100644 index ee42469..0000000 --- a/src/fbgui.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - * - * - * Main class of the fbgui: - * - Manages display of components and their communications - * - */ - -#ifndef FBGUI_H -#define FBGUI_H - -#include -#include -#include -#include - -// Internal default settings -#define DEFAULT_URL "http://www.google.com" -#define DEFAULT_DOWNLOAD_DIR "/tmp/fbgui" -#define DEFAULT_CONFIG_PATH "/etc/fbgui.conf" -#define DEFAULT_LOG_FILE_PATH "/tmp/fbgui.log" -#define DEFAULT_UPDATE_INTERVAL 1; -#define DEFAULT_QRC_HTML_DIR ":/html" -#define DEFAULT_FILE_TRIGGER "/tmp/fbgui/trigger" - -// Global settings variables -extern QString logFilePath; -extern QString ipConfigFilePath; -extern QThread dmThread; -extern QString serialLocation; -extern QString fileToTriggerURL; -extern QString sessionID; -extern QString binPath; -extern QString downloadPath; -extern QUrl baseURL; -extern int debugMode; -extern int updateInterval; - -class fbgui: public QMainWindow { -Q_OBJECT - -public: - fbgui(); - ~fbgui(); - -public slots: - void init(); - -private: - //------------------- - // layout setup: - //------------------- - // Sets the layout depending on the debug mode: - // no debug or debugMode = 0 -> only browser shown. - // debugMode = 1 -> split main window in browser and debug console. - void setupLayout(); - // Create all actions for the GUI. (Currently only quit.) - void createActions(); - // Create a debug console widget as QTextEdit in order to print debug messages - // directly within the GUI. This was needed since ttys can't really be used - // for debugging purposes in the preboot environment. - void createDebugConsole(); - - //---------------------------------------- - // control the display of components: - //---------------------------------------- - // watches for the file triggering the loading of the URL. - // the file can be specified by the corresponding option. - void watchForTrigger(); - bool checkHost() const; - void loadURL(); - QByteArray generatePOSTData(); - - //---------------------------------- - // widgets constituing the gui: - //---------------------------------- - // QWebView for displaying internet content - QWebView* _webView; - // QSplitter to split the main window in two resizable frames. - QSplitter* _splitter; - // QTextEdit implementing a minimalistic debug console. - QTextEdit* _debugConsole; - - //------------------ - // action list: - //------------------ - // closes the main window provoking the application to quit. - QAction* _quit; - // triggers toggleDebugConsole() - QAction* _toggleDebugConsole; - - // watcher to detect changes in the observed directory. - QFileSystemWatcher* _watcher; - -private slots: - // toggles debug console when action _toggleDebugConsole happens. - void toggleDebugConsole(); - - // This function is triggered by fileChanged Signal of _watcher. - // It deletes _watcher, since we don't need it anymore and tries to load URL. - void prepareURLLoad(); - void loadURLDone(bool success); - - // shut off the system - void performShutDown(); - // reboot the system - void performReboot(); - // shows "loading system" page - void loadSystem(); - // prepares kexec by loading downloaded initramfs, kernel into kexec - void prepareKexec(); - // executes: kexec -e - void runKexec(); -}; - -#endif // FBGUI_H diff --git a/src/fbgui.pro b/src/fbgui.pro deleted file mode 100644 index 701402b..0000000 --- a/src/fbgui.pro +++ /dev/null @@ -1,50 +0,0 @@ -TEMPLATE = app -TARGET = fbgui -CONFIG += qt \ - debug -QT += core \ - gui \ - network \ - webkit -LIBS += -L/usr/local/qjson/lib \ - -lqjson \ - -L/usr/local/Qxt/lib \ - -lQxtCore \ - -L/usr/lib \ - -lsysfs \ - -lnl \ - -lusb-1.0 \ - -L/usr/local/lib \ - -lcustomdhcpcd -INCLUDEPATH += /usr/local/qjson/include \ - /usr/local/Qxt/include \ - /usr/local/Qxt/include/QxtCore \ - /usr/include/sysfs \ - /usr/include/libusb-1.0 \ - /usr/include/net \ - /usr/include/netlink \ - /usr/include/netlink/route \ - /usr/include/arpa \ - ./../customdhcpcd/src -HEADERS += ../common/fbgui.h \ - downloadmanager.h \ - fbgui.h \ - interfaceconfiguration.h \ - javascriptinterface.h \ - loggerengine.h \ - ndgui.h \ - networkdiscovery.h \ - networkmanager.h \ - sysinfo.h -SOURCES += networkdiscovery.cpp \ - networkmanager.cpp \ - ndgui.cpp \ - interfaceconfiguration.cpp \ - sysinfo.cpp \ - loggerengine.cpp \ - javascriptinterface.cpp \ - downloadmanager.cpp \ - fbgui.cpp \ - main.cpp -FORMS += -RESOURCES += fbgui.qrc diff --git a/src/fbgui.qrc b/src/fbgui.qrc deleted file mode 100644 index a5333c5..0000000 --- a/src/fbgui.qrc +++ /dev/null @@ -1,36 +0,0 @@ - - - html/background.png - html/continueBoot.html - html/loadsystem.css - html/loadsystem.html - html/networkdiscovery.css - html/networkdiscovery.html - html/networkdiscovery_userchoice.html - html/old.png - html/preload.css - html/preload.html - html/preload-debug.html - html/js/jquery-1.6.4.min.js - html/js/jquery-ui-1.8.16.min.js - html/js/networkDiscovery.js - html/css/jquery-ui-1.8.16.css - html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png - html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png - html/css/images/ui-bg_flat_10_000000_40x100.png - html/css/images/ui-bg_glass_65_ffffff_1x400.png - html/css/images/ui-bg_glass_100_f6f6f6_1x400.png - html/css/images/ui-bg_glass_100_fdf5ce_1x400.png - html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png - html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png - html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png - html/css/images/ui-icons_228ef1_256x240.png - html/css/images/ui-icons_222222_256x240.png - html/css/images/ui-icons_ef8c08_256x240.png - html/css/images/ui-icons_ffd27a_256x240.png - html/css/images/ui-icons_ffffff_256x240.png - html/networkdiscovery_debug.html - html/networkdiscovery_userchoice_debug.html - html/images/loading.gif - - diff --git a/src/fbgui/downloadmanager.cpp b/src/fbgui/downloadmanager.cpp new file mode 100644 index 0000000..653bc7b --- /dev/null +++ b/src/fbgui/downloadmanager.cpp @@ -0,0 +1,215 @@ +#include "downloadmanager.h" + +// static counter to save the number of successfully downloaded files. +int DownloadManager::_downloaded = 0; +// ------------------------------------------------------------------------------------------------------- +// Initialisation +// ------------------------------------------------------------------------------------------------------- +// Constructor initialises a QNetworkAccessManager needed to create/received download requests/replies +// This object is then moved to the thread for the download manager, to ensure that downloads +// are done in a separate thread (to avoid GUI blocking.) +// The flag "_dip" starts as false, since no download is in progress. +// This flag is needed to control queueing functionality. +// Lastly the given download directory's existance is checked. (see below) + +DownloadManager::DownloadManager() { + qxtLog->debug() << "Initializing download manager..."; + checkDownloadDirectory(); + _qnam = new QNetworkAccessManager(); + _qnam->moveToThread(&dmThread); + _dip = false; +} +// Destructor +DownloadManager::~DownloadManager() { + delete _qnam; +} +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::checkDownloadDirectory() { + // check if downloadPath exists, if not create it. + _downloadDir = QDir(downloadPath); + if (!_downloadDir.exists()) { + qxtLog->debug() << "[dm] Download directory: " << _downloadDir.path() << " doesn't exist."; + // try to create the directory + if (QDir::current().mkdir(downloadPath)) + qxtLog->debug() << "[dm] Created download directory: " << _downloadDir.path(); + else { + qxtLog->debug() << "[dm] Failed to create directory: " << _downloadDir.path(); + // try to save to /tmp/fbgui + _downloadDir.setPath(QDir::tempPath() + "/fbgui"); + if (!_downloadDir.exists()) { + if (QDir::current().mkdir(QDir::tempPath() + "/fbgui")) + qxtLog->debug() << "[dm] Successfully created: " << _downloadDir.absolutePath(); + else { + // just in case + qxtLog->debug() << "[dm] Failed to create: " << _downloadDir.absolutePath(); + qxtLog->debug() << "[dm] Exiting..."; + exit( EXIT_FAILURE); + } + } else + qxtLog->debug() << "[dm] " << _downloadDir.absolutePath() << " already exists."; + } + } else + qxtLog->debug() << "[dm] Download directory: " << _downloadDir.absolutePath() + << " already exists."; + + qxtLog->debug() << "[dm] Saving downloads to: " << _downloadDir.absolutePath(); + downloadPath = _downloadDir.absolutePath(); +} +// ------------------------------------------------------------------------------------------------------- +// Public access +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::downloadFile(const QString& filename) { + QUrl fileUrl(baseURL.resolved(QUrl(filename))); + this->processDownloadRequest(fileUrl); +} +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::downloadFile(const QUrl& fileUrl) { + this->processDownloadRequest(fileUrl); +} +// ------------------------------------------------------------------------------------------------------- +// Private functions handling download requests and queueing +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::processDownloadRequest(const QUrl& url) { + if (url.isEmpty()) { + qxtLog->debug() << "[dm] No URL specified for download."; + return; + } + qxtLog->debug() << "[dm] Enqueueing: " << url.toString(); + _downloadQueue.enqueue(url); + if (_dip) { + // download in progress, return. + qxtLog->debug() << "[dm] Download in progress! Queued:" << url.toString() << "(" + << _downloadQueue.size() << " in queue)"; + return; + } + // no running downloads: start next in queue + startNextDownload(); +} +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::startNextDownload() { + //QWSServer::instance()->setCursorVisible(false); + if (_downloadQueue.isEmpty()) { + emit downloadQueueEmpty(); + qxtLog->debug() << "[dm] Download manager ready. (1)"; + return; + } + qxtLog->debug() << "[dm] Starting next download: " << _downloadQueue.head().toString() << " (" + << _downloadQueue.size() - 1 << " in queue.)"; + + // dequeue next URL to download. + QUrl url = _downloadQueue.dequeue(); + + // get filename from URL. + QString tmp = url.path(); + tmp.remove(0, tmp.lastIndexOf(QChar('/')) + 1); + + // check if filename exists on target file system + if (_downloadDir.exists(tmp)) { + qxtLog->debug() << "[dm] File already exists: " << _downloadDir.absoluteFilePath(tmp); + _outfile.setFileName( + QString(_downloadDir.absolutePath() + "/" + tmp + ".\%1").arg(_downloaded)); + } else + _outfile.setFileName(_downloadDir.absoluteFilePath(tmp)); + qxtLog->debug() << "[dm] Saving to: " << _outfile.fileName(); + + // try to open for writing + if (!_outfile.open(QIODevice::WriteOnly)) { + qxtLog->debug() << "[dm] No write access to " << _outfile.fileName() + << " . Skipping download..."; + return; + } + + // send the request for the file + QNetworkRequest request(url); + _currentDownload = _qnam->get(request); + _lastProgress = 0; + _currentProgress = 0; + _dip = true; + time.start(); + QObject::connect(_currentDownload, SIGNAL(readyRead()), this, SLOT( + downloadReady())); + QObject::connect(_currentDownload, SIGNAL(metaDataChanged()), this, SLOT( + processMetaInfo())); + QObject::connect(_currentDownload, SIGNAL(downloadProgress(qint64, qint64)), this, + SLOT(downloadProgress(qint64, qint64))); + QObject::connect(_currentDownload, SIGNAL(finished()), this, SLOT( + downloadFinished())); +} +// ------------------------------------------------------------------------------------------------------- +// Private slots to handle a download in progress +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::processMetaInfo() { + // fetch filesize from header & filename from URL (for now) + const QByteArray cltag = "Content-Length"; + QByteArray clinfo = _currentDownload->rawHeader(cltag); + QFileInfo fi(_outfile); + qxtLog->debug() << "[dm] Download Info: " << fi.fileName() << " (Size: " << clinfo.toDouble() + << ")"; + emit downloadInfo(fi.fileName(), clinfo.toDouble()); +} +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::downloadReady() { + // data ready, save it + _outfile.write(_currentDownload->readAll()); +} +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::downloadProgress(qint64 bytesIn, qint64 bytesTotal) { + if (bytesIn > bytesTotal || bytesTotal <= 0) { + qxtLog->debug() << "[dm] downloadProgress invalid values:" << "In:" << bytesIn + << " / Total: " << bytesTotal; + return; + } + // calculate current speed + double speed = bytesIn * 1000 / time.elapsed(); + QString unit; + if (speed < 1024) { + unit = "bytes/sec"; + } else if (speed < 1024 * 1024) { + speed /= 1024; + unit = "KB/s"; + } else { + speed /= 1024 * 1024; + unit = "MB/s"; + } + // update progress only if difference higher than the updateInterval setting + _currentProgress = ((bytesIn * 100) / bytesTotal); + if (_currentProgress - _lastProgress >= updateInterval) { + _lastProgress = _currentProgress; + emit + updateProgress(_currentProgress, speed, unit); + qxtLog->debug() << "[dm] Download progress of " << _currentDownload->url().toString() << ": " + << bytesIn << "/" << bytesTotal << "(" << _currentProgress << "\%)"; + } +} +// ------------------------------------------------------------------------------------------------------- +void DownloadManager::downloadFinished() { + // check for errors + if (_currentDownload->error()) { + _outfile.close(); + _outfile.remove(); + int statusCode = + _currentDownload->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + qxtLog->debug() << "[dm] Download of " << _currentDownload->url().toString() + << " failed with HTTP error code: " << statusCode; + emit + notify(QString("Download failed! HTTP Status Code: %1").arg(statusCode)); + _currentDownload->deleteLater(); + } else { + // end download + _outfile.close(); + _downloaded++; + qxtLog->debug() << "[dm] Download of " << _currentDownload->url().toString() + << " finished. (downloaded = " << _downloaded << ")"; + emit + notify(QString("Successfully downloaded %1").arg(_currentDownload->url().toString())); + _currentDownload->deleteLater(); + } + _dip = false; + // process next in queue, if any + if (_downloadQueue.isEmpty()) { + emit downloadQueueEmpty(); + qxtLog->debug() << "[dm] Download manager ready. (2)"; + return; + } + startNextDownload(); +} diff --git a/src/fbgui/downloadmanager.h b/src/fbgui/downloadmanager.h new file mode 100644 index 0000000..62df4bc --- /dev/null +++ b/src/fbgui/downloadmanager.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + * + * + * Class managing download requests: + * - provides queueing functionality + * - static info: filename, filesize + * - dynamic info: download progress, current speed + * + */ + +#ifndef DOWNLOADMANAGER_H +#define DOWNLOADMANAGER_H + +#include "fbgui.h" + +extern bool debug; +extern QUrl baseURL; +extern QString binPath; +extern QString downloadPath; +extern int updateInterval; + +class DownloadManager: public QObject { +Q_OBJECT + +public: + DownloadManager(); + ~DownloadManager(); + QTime time; + +private: + // checks for valid download directory, ran once in constructor + void checkDownloadDirectory(); + // private control function for queueing mechanism. + void processDownloadRequest(const QUrl& url); + + // base objects for downloading + QNetworkAccessManager* _qnam; + QQueue _downloadQueue; + QNetworkReply* _currentDownload; + QFile _outfile; + QDir _downloadDir; + // download progress variables + int _currentProgress, _lastProgress; + // download in progress flag + bool _dip; + // static counter + static int _downloaded; + +signals: + // notify sends a message to the javascript interface to be evaluated there + void notify(const QString& msg); + // downloadInfo sends static information (name, size) to the interface. + void downloadInfo(const QString& filename, const double& filesize); + // updateProgress sends download progress information to the interface. + void updateProgress(const int& percent, const double& speed, const QString& unit); + // signal emitted when download queue is empty. + void downloadQueueEmpty(); + +public slots: + // public slots to receive download requests. + void downloadFile(const QUrl& fileUrl); + // convenience function + void downloadFile(const QString& fileUrl); + +private slots: + // private slots to manage the downloading process + void startNextDownload(); + void processMetaInfo(); + void downloadReady(); + void downloadProgress(qint64 bytesIn, qint64 bytesTotal); + void downloadFinished(); +}; + +#endif // DOWNLOADMANAGER_H diff --git a/src/fbgui/fbgui.cpp b/src/fbgui/fbgui.cpp new file mode 100644 index 0000000..22a2ac6 --- /dev/null +++ b/src/fbgui/fbgui.cpp @@ -0,0 +1,492 @@ +#include "fbgui.h" +#include "sysinfo.h" +#include "loggerengine.h" +#include "downloadmanager.h" +#include "javascriptinterface.h" + +#include +#include +#include +#include + +QThread dmThread; +QString logFilePath(""); +QString ipConfigFilePath(""); +QString binPath(""); +QUrl baseURL(""); +QString downloadPath(""); +int updateInterval = -1; +QString fileToTriggerURL(""); +QString serialLocation(""); +QString sessionID(""); +int debugMode = -1; + +//------------------------------------------------------------------------------------------- +/** + * A constructor. + * + * The constructor of the fbgui class. It initializes the main objects + * which are needed while the program is running. + * The appearance of the webView is here also defined. + * + * @see JavascriptInterface + * @see DownloadManager + */ +fbgui::fbgui() { +} +fbgui::~fbgui() { + dmThread.quit(); +} + + + +/** + * init function. + */ +void fbgui::init() { + // start fbgui + qxtLog->debug() << "Initializing fbgui..."; + + setupLayout(); + createActions(); + + // initialize javascript interface + JavascriptInterface* jsi = new JavascriptInterface( + _webView->page()->mainFrame()); + QObject::connect(jsi, SIGNAL(quitFbgui()), this, SLOT(close())); + QObject::connect(jsi, SIGNAL(shutDownClient()), this, + SLOT(performShutDown())); + QObject::connect(_webView->page()->mainFrame(), SIGNAL( + javaScriptWindowObjectCleared()), jsi, SLOT(attachToDOM())); + + // initialize download manager + DownloadManager* dm = new DownloadManager(); + QObject::connect(dm, SIGNAL(downloadInfo(const QString&, const double&)), + jsi, SLOT(downloadInfo(const QString&, const double&))); + QObject::connect(dm, SIGNAL(notify(const QString&)), jsi, + SLOT(notify(const QString&))); + QObject::connect(jsi, SIGNAL(requestFile(const QString&)), dm, + SLOT(downloadFile(const QString&))); + QObject::connect( + dm, + SIGNAL(updateProgress(const int&, const double&, const QString&)), + jsi, + SLOT(updateProgressBar(const int&, const double&, const QString&))); + QObject::connect(dm, SIGNAL(downloadQueueEmpty()), jsi, SLOT( + callbackOnFinished())); + QObject::connect(dm, SIGNAL(downloadQueueEmpty()), this, SLOT(loadSystem())); + + // move download manager to its own thread + dm->moveToThread(&dmThread); + dmThread.start(); + + // show "waiting for internet" page until triggered. + if (debugMode > -1) { + _webView->load(QUrl("qrc:/html/preload-debug.html")); + } else { + _webView->load(QUrl("qrc:/html/preload.html")); + } + + // watcher is not needed anymore since we guarantee internet connection with the networkDiscovery. + // start watching for fileToTriggerURL + //watchForTrigger(); + loadURL(); + + // set properties + setWindowTitle("fbgui"); + setAttribute(Qt::WA_QuitOnClose, true); + setWindowFlags(Qt::FramelessWindowHint); + showFullScreen(); + this->show(); +} +//------------------------------------------------------------------------------------------- +// Layout / actions setup +//------------------------------------------------------------------------------------------- +/** + * This method sets the used Layout. + * + * This method sets the used Layout. Possible layout are: + * - browser mode: only the browser is visible + * - debug mode: the screen is divided into the browser and a debug + * out console + */ +void fbgui::setupLayout() { + // setup layout of the gui: debug split or browser + _webView = new QWebView(this); + if (debugMode == 1) { + // split main window in browser & debug console + createDebugConsole(); + _splitter = new QSplitter(Qt::Vertical, this); + _splitter->addWidget(_webView); + _splitter->addWidget(_debugConsole); + setCentralWidget(_splitter); + } else + setCentralWidget(_webView); +} +//------------------------------------------------------------------------------------------- +/** + * This method enables a shortcut for closing the program. + * The shortcut itself is not configurable: CTRL + X + */ +void fbgui::createActions() { + _quit = new QAction(tr("&quit"), this); + _quit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X)); + this->addAction(_quit); + connect(_quit, SIGNAL(triggered()), this, SLOT(close())); +} +//------------------------------------------------------------------------------------------- +// File system watching +//------------------------------------------------------------------------------------------- +/** + * This method sets a "watchdog" to a special file. + * + * This method sets a "watchdog" to a special file. If needed it creates the + * file which it has to watch over. It than connects a QFileSystemWatcher with + * this file. If changes happen to this file, the + * fbgui::checkForTrigger(const QString& dirname) method will be called. + * + */ +void fbgui::watchForTrigger() { + // check if fileToTriggerURL already exists + QFile file(fileToTriggerURL); + if (file.exists()) { + qxtLog->debug() << "[watcher] " << fileToTriggerURL << " found."; + // try to load URL + loadURL(); + } else { + // create it + if (file.open(QIODevice::WriteOnly)) { + qxtLog->debug() << "[gui] Created: " << fileToTriggerURL; + file.close(); + } else { + qxtLog->debug() << "[gui] Creation of " << fileToTriggerURL + << " failed!"; + qxtLog->debug() << "[gui] Exiting in 5 seconds..."; + QTimer::singleShot(5000, this, SLOT(close())); + } + } + // watch the path to trigger file + qxtLog->debug() << "[watcher] Watching " << fileToTriggerURL; + _watcher = new QFileSystemWatcher(QStringList(fileToTriggerURL), this); +QObject::connect(_watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(prepareURLLoad())); + +} +//------------------------------------------------------------------------------------------- +/** + * This method checks if the trigger was valid. + * + * This method checks if the trigger was valid. If yes, + * we have received an IP Address an can load the main screen. + * If not, something some error happened. + * + * @see fbgui::checkHost() + * @see fbgui::loadURL() + */ +void fbgui::prepareURLLoad() { + qxtLog->debug() << "[watcher] " << fileToTriggerURL << " changed!"; + // disconnect _watcher, his job is done + qxtLog->debug() << "[watcher] disconnected."; + _watcher->disconnect(this); + _watcher->deleteLater(); + // try to load URL + loadURL(); +} +//------------------------------------------------------------------------------------------- +// Preparations for URL load +//------------------------------------------------------------------------------------------- +/** + * This method checks the existance of the host. + * + * This method checks if the host exists / can be found. + * The host is from the URL given through the configuration. + */ +bool fbgui::checkHost() const { + QHostInfo hostInfo = QHostInfo::fromName(baseURL.host()); + if (hostInfo.error() != QHostInfo::NoError) { + qxtLog->debug() << "[gui] Lookup of " << baseURL.host() << "failed."; + qxtLog->debug() << "[gui] Host can not be reached."; + return false; + } else { + qxtLog->debug() << "[gui] Lookup of " << baseURL.host() << " succeeded."; + return true; + } +} +//------------------------------------------------------------------------------------------- +/** + * This method tries loads the URL. + * + * This method loads the main screen via an POST request. If also disconnects the watcher + * of the file, (Watcher is set in the fbgui::watchForTrigger() method). + * and generates the POST data body. + * + * @see fbgui::watchForTrigger() + * @see fbgui::generatePOSTData() + */ +void fbgui::loadURL() { + if (checkHost()) { + qxtLog->debug() << "[gui] Loading URL: " << baseURL.toString() << " ..."; + + // Generate POST identification data needed by PBS. + QByteArray postData = generatePOSTData(); + QNetworkRequest req(baseURL); + + // show cursor again since user is about to interact. + //QWSServer::instance()->setCursorVisible(true); + QObject::connect(_webView, SIGNAL(loadFinished(bool)), this, SLOT(loadURLDone(bool))); + _webView->load(req, QNetworkAccessManager::PostOperation, postData); + } + // TODO: error page if no host. +} +void fbgui::loadURLDone(bool success) { + // done contains the success of the loading: false / true + if (!success) { + qxtLog->debug() << "[gui] Loading failed. URL: " + << _webView->url().toString(); + qxtLog->debug() << "[gui] You can quit with CTRL + X ..."; + // TODO handle failure properly... + } else { + qxtLog->debug() << "[gui] Loaded URL: " << _webView->url().toString(); + } +} +//------------------------------------------------------------------------------------------- +/** + * This method generates the POST data body. + * + * This method generates the POST data body. The body contains the + * MAC address, an hardwarehash and a specific serial number. + * The hardwarehash is a MD5 hash over the MAC address and the + * mainboard serial number. + * The specific serial number is set at the creation of the usb boot stick. + * This file has to be present on the directory specified in + * the configuration for this to work. + * + * @see SysInfo::getMACAddress() + * @see SysInfo::getMainboardSerial() + */ +QByteArray fbgui::generatePOSTData() { + qxtLog->debug() << "[gui] Generating POST data..."; + // use MAC address as base data + SysInfo si; + QByteArray data(si.getInfo("mac").toUtf8()); + // append mainboard serial to the mac address for more unique hardwarehash + QByteArray mbserial(si.getInfo("mbserial").toUtf8()); + if (!mbserial.isEmpty()) + data.append(mbserial); + else { + qxtLog->debug() + << "[gui] Mainboard serial was empty. Not appending to base hash data."; + } + qxtLog->debug() << "[post] Hashing: " << data; + // generate MD5 hash of data + QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); + qxtLog->debug() << "[post] MD5 Hash: " << hash.toHex(); + + // fetch serial number from usb + QByteArray serial; + QFile file(serialLocation); + if (!file.open(QIODevice::ReadOnly)) { + qxtLog->debug() << "[post] No such file: " << file.fileName(); + } + // everything ok, read data + serial = file.readAll(); + file.close(); + serial.chop(1); // chop EOF + qxtLog->debug() << "[post] Serial number is: " << serial; + + // construct final byte array + QByteArray postData("mac="); + postData.append(si.getInfo("mac")); + postData.append("&hardwarehash=" + hash.toHex()); + postData.append("&serialnumber=" + serial); + qxtLog->debug() << "[post] POST data: " << postData; + return postData; +} + +//------------------------------------------------------------------------------------------- +// Shutdown / Reboot of the client +//------------------------------------------------------------------------------------------- +// TODO One function for reboot and shutdown, with parameter for the action. +// for example: doSystemCall(_REBOOT_); +/** + * This method performs the shutdown of the client. + * + * This method performs the shutdown of the client. It is triggered by the + * JavascriptInterface::shutDownClient() signal which will be emited in the + * JavascriptInterface::shutDown() method. + * This method writes the character 'o' in /proc/sysrq-trigger + * which will shutdown the computer immediatly. + * (See linux magic keys) + * + * @see JavascriptInterface::shutDownClient() + * @see JavascriptInterface::shutDown() + */ +void fbgui::performShutDown() { + QFile file("/proc/sysrq-trigger"); + if (file.open(QIODevice::WriteOnly)) { + file.write("o"); + file.close(); + } else { + qxtLog->debug() << "[gui] Could not open /proc/sysrq-trigger"; + } +} +//------------------------------------------------------------------------------------------- +/** + * This method performs the reboot of the client. + * + * This method performs the reboot of the client. It is triggered by the + * JavascriptInterface::rebootClient() signal which will be emited in the + * JavascriptInterface::reboot() method. + * This method writes the character 'b' in /proc/sysrq-trigger + * which will shutdown the computer immediatly. + * (See linux magic keys) + * + * @see JavascriptInterface::rebootClient() + * @see JavascriptInterface::reboot() + */ +void fbgui::performReboot() { + QFile file("/proc/sysrq-trigger"); + if (file.open(QIODevice::WriteOnly)) { + file.write("b"); + file.close(); + } else { + qxtLog->debug() << "[gui] Could not open /proc/sysrq-trigger"; + } +} +//------------------------------------------------------------------------------------------- +// Preparing Kernel Switch per kexec (initiating Stage 3) +//------------------------------------------------------------------------------------------- +void fbgui::loadSystem() { + //show loading system page. + //_webView->disconnect(this); + //QObject::connect(_webView, SIGNAL(loadFinished(bool)), this, SLOT(prepareKexec())); + _webView->load(QUrl("qrc:/html/loadsystem.html")); + QTimer::singleShot(1000, this, SLOT(prepareKexec())); +} +//------------------------------------------------------------------------------------------- +/** + * This method prepares kexec. + * + * The kernel command line file that should have been downloaded from the Preboot-Server + * and the ip config file (created by udhcpc) are merged into the final completed KCL. + * + * A process is then started to load the kernel, initramfs and kcl into kexec. + * The process tries to execute kexec -l with these parameters. + * + * If this succeeds, runKexec() is called + * + * @see fbgui::runKexec() + * + */ +void fbgui::prepareKexec() { + + qxtLog->debug() << "[gui] Preparing kexec ..."; + // try to read KCL file that was downloaded. + QFile file(downloadPath + "/kcl"); + if (!file.open(QIODevice::ReadOnly)) { + qxtLog->debug() << "[gui] No such file: " << file.fileName(); + } + // everything ok, read data. + QString kcl = file.readAll(); + file.close(); + qxtLog->debug() << "[gui] KCL from PBS: " << kcl; + + // try to read ipconfig file generated by udhcpc. + file.setFileName("/tmp/ip_config_fbgui"); + if (!file.open(QIODevice::ReadOnly)) { + qxtLog->debug() << "[gui] No such file: " << file.fileName(); + } + // everything ok, read data. + QString ipConfig = file.readAll(); + file.close(); + qxtLog->debug() << "[gui] IP config: " << ipConfig; + + // append ipConfig + kcl.append(" ip="); + kcl.append(ipConfig); + qxtLog->debug() << "[gui] Complete KCL: " << kcl; + + // load the kernel + initramfs + append of kcl into kexec. + QProcess *process = new QProcess(this); + QString cmdline = "kexec -l " + downloadPath.toUtf8() + "/kernel --initrd=" + + downloadPath.toUtf8() + "/initramfs --append=\"" + kcl.toUtf8() + + "\""; + qxtLog->debug() << "[gui] kexec cmdline: " << cmdline; + process->start(cmdline); + bool ret = process->waitForFinished(); + if (!ret) { + qxtLog->debug() << "[gui] Failed to execute: " << cmdline; + qxtLog->debug() << "[gui] Exiting in 5 seconds..."; + QTimer::singleShot(5000, this, SLOT(close())); + } else { + qxtLog->debug() << "[gui] Kexec load was successfull."; + if (debugMode < 0) { + // if process successfully finished, try to run kexec -e + runKexec(); + } else { + qxtLog->debug() + << "[gui] Skipping execution of kexec - open debug shell."; + qxtLog->debug() + << "[gui] To start the system execute \"kexec -e\" in your shell."; + close(); + } + } +} +//------------------------------------------------------------------------------------------- +/** + * This method tries to execute: kexec -e + * + * This method tries to execute: kexec -e + * + */ +void fbgui::runKexec() { + QProcess *process = new QProcess(this); + process->start("kexec -e"); + if (!process->waitForStarted()) { + qxtLog->debug() << "[gui] Failed to execute: kexec -e"; + qxtLog->debug() << "[gui] Exiting in 5 seconds..."; + QTimer::singleShot(5000, this, SLOT(close())); + //TODO: Handle failure properly... + } +} +//------------------------------------------------------------------------------------------- +// Debug console setup / control +//------------------------------------------------------------------------------------------- +/** + * This method creates a debug console as a widget. + * + * It is basicly a QTextEdit widget as provided by QT's Framework. + * An action to toggle this widget is implemented (CTRL + D). + * + * @see fbgui::toggleDebugConsole() + */ +void fbgui::createDebugConsole() { + // create the debug console widget + _debugConsole = new QTextEdit(this); + _debugConsole->setWindowFlags(Qt::FramelessWindowHint); + // fanciness + QPalette pal; + pal.setColor(QPalette::Base, Qt::black); + _debugConsole->setPalette(pal); + _debugConsole->setTextColor(Qt::white); + // enable custom logger engine + qxtLog->addLoggerEngine("fb_logger", new LoggerEngine_fb(_debugConsole)); + //qxtLog->initLoggerEngine("fb_logger"); + qxtLog->setMinimumLevel("fb_logger", QxtLogger::DebugLevel); + // CTRL + D toggles debug window + _toggleDebugConsole = new QAction(tr("&toggleDebug"), this); + _toggleDebugConsole->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); + addAction(_toggleDebugConsole); + connect(_toggleDebugConsole, SIGNAL(triggered()), this, SLOT( + toggleDebugConsole())); +} +//------------------------------------------------------------------------------------------- +/** + * This method toggles the debug console. + * + * Toggle the visibility of the debug console if the action _toggleDebugConsole is triggered. + * + * @see fbgui::createDebugConsole() + */ +void fbgui::toggleDebugConsole() { + (_debugConsole->isVisible()) ? _debugConsole->hide() : _debugConsole->show(); +} diff --git a/src/fbgui/fbgui.h b/src/fbgui/fbgui.h new file mode 100644 index 0000000..ee42469 --- /dev/null +++ b/src/fbgui/fbgui.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + * + * + * Main class of the fbgui: + * - Manages display of components and their communications + * + */ + +#ifndef FBGUI_H +#define FBGUI_H + +#include +#include +#include +#include + +// Internal default settings +#define DEFAULT_URL "http://www.google.com" +#define DEFAULT_DOWNLOAD_DIR "/tmp/fbgui" +#define DEFAULT_CONFIG_PATH "/etc/fbgui.conf" +#define DEFAULT_LOG_FILE_PATH "/tmp/fbgui.log" +#define DEFAULT_UPDATE_INTERVAL 1; +#define DEFAULT_QRC_HTML_DIR ":/html" +#define DEFAULT_FILE_TRIGGER "/tmp/fbgui/trigger" + +// Global settings variables +extern QString logFilePath; +extern QString ipConfigFilePath; +extern QThread dmThread; +extern QString serialLocation; +extern QString fileToTriggerURL; +extern QString sessionID; +extern QString binPath; +extern QString downloadPath; +extern QUrl baseURL; +extern int debugMode; +extern int updateInterval; + +class fbgui: public QMainWindow { +Q_OBJECT + +public: + fbgui(); + ~fbgui(); + +public slots: + void init(); + +private: + //------------------- + // layout setup: + //------------------- + // Sets the layout depending on the debug mode: + // no debug or debugMode = 0 -> only browser shown. + // debugMode = 1 -> split main window in browser and debug console. + void setupLayout(); + // Create all actions for the GUI. (Currently only quit.) + void createActions(); + // Create a debug console widget as QTextEdit in order to print debug messages + // directly within the GUI. This was needed since ttys can't really be used + // for debugging purposes in the preboot environment. + void createDebugConsole(); + + //---------------------------------------- + // control the display of components: + //---------------------------------------- + // watches for the file triggering the loading of the URL. + // the file can be specified by the corresponding option. + void watchForTrigger(); + bool checkHost() const; + void loadURL(); + QByteArray generatePOSTData(); + + //---------------------------------- + // widgets constituing the gui: + //---------------------------------- + // QWebView for displaying internet content + QWebView* _webView; + // QSplitter to split the main window in two resizable frames. + QSplitter* _splitter; + // QTextEdit implementing a minimalistic debug console. + QTextEdit* _debugConsole; + + //------------------ + // action list: + //------------------ + // closes the main window provoking the application to quit. + QAction* _quit; + // triggers toggleDebugConsole() + QAction* _toggleDebugConsole; + + // watcher to detect changes in the observed directory. + QFileSystemWatcher* _watcher; + +private slots: + // toggles debug console when action _toggleDebugConsole happens. + void toggleDebugConsole(); + + // This function is triggered by fileChanged Signal of _watcher. + // It deletes _watcher, since we don't need it anymore and tries to load URL. + void prepareURLLoad(); + void loadURLDone(bool success); + + // shut off the system + void performShutDown(); + // reboot the system + void performReboot(); + // shows "loading system" page + void loadSystem(); + // prepares kexec by loading downloaded initramfs, kernel into kexec + void prepareKexec(); + // executes: kexec -e + void runKexec(); +}; + +#endif // FBGUI_H diff --git a/src/fbgui/fbgui.pro b/src/fbgui/fbgui.pro new file mode 100644 index 0000000..701402b --- /dev/null +++ b/src/fbgui/fbgui.pro @@ -0,0 +1,50 @@ +TEMPLATE = app +TARGET = fbgui +CONFIG += qt \ + debug +QT += core \ + gui \ + network \ + webkit +LIBS += -L/usr/local/qjson/lib \ + -lqjson \ + -L/usr/local/Qxt/lib \ + -lQxtCore \ + -L/usr/lib \ + -lsysfs \ + -lnl \ + -lusb-1.0 \ + -L/usr/local/lib \ + -lcustomdhcpcd +INCLUDEPATH += /usr/local/qjson/include \ + /usr/local/Qxt/include \ + /usr/local/Qxt/include/QxtCore \ + /usr/include/sysfs \ + /usr/include/libusb-1.0 \ + /usr/include/net \ + /usr/include/netlink \ + /usr/include/netlink/route \ + /usr/include/arpa \ + ./../customdhcpcd/src +HEADERS += ../common/fbgui.h \ + downloadmanager.h \ + fbgui.h \ + interfaceconfiguration.h \ + javascriptinterface.h \ + loggerengine.h \ + ndgui.h \ + networkdiscovery.h \ + networkmanager.h \ + sysinfo.h +SOURCES += networkdiscovery.cpp \ + networkmanager.cpp \ + ndgui.cpp \ + interfaceconfiguration.cpp \ + sysinfo.cpp \ + loggerengine.cpp \ + javascriptinterface.cpp \ + downloadmanager.cpp \ + fbgui.cpp \ + main.cpp +FORMS += +RESOURCES += fbgui.qrc diff --git a/src/fbgui/fbgui.qrc b/src/fbgui/fbgui.qrc new file mode 100644 index 0000000..a5333c5 --- /dev/null +++ b/src/fbgui/fbgui.qrc @@ -0,0 +1,36 @@ + + + html/background.png + html/continueBoot.html + html/loadsystem.css + html/loadsystem.html + html/networkdiscovery.css + html/networkdiscovery.html + html/networkdiscovery_userchoice.html + html/old.png + html/preload.css + html/preload.html + html/preload-debug.html + html/js/jquery-1.6.4.min.js + html/js/jquery-ui-1.8.16.min.js + html/js/networkDiscovery.js + html/css/jquery-ui-1.8.16.css + html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png + html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png + html/css/images/ui-bg_flat_10_000000_40x100.png + html/css/images/ui-bg_glass_65_ffffff_1x400.png + html/css/images/ui-bg_glass_100_f6f6f6_1x400.png + html/css/images/ui-bg_glass_100_fdf5ce_1x400.png + html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png + html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png + html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png + html/css/images/ui-icons_228ef1_256x240.png + html/css/images/ui-icons_222222_256x240.png + html/css/images/ui-icons_ef8c08_256x240.png + html/css/images/ui-icons_ffd27a_256x240.png + html/css/images/ui-icons_ffffff_256x240.png + html/networkdiscovery_debug.html + html/networkdiscovery_userchoice_debug.html + html/images/loading.gif + + diff --git a/src/fbgui/html/background.png b/src/fbgui/html/background.png new file mode 100644 index 0000000..7e374f9 Binary files /dev/null and b/src/fbgui/html/background.png differ diff --git a/src/fbgui/html/continueBoot.html b/src/fbgui/html/continueBoot.html new file mode 100644 index 0000000..89020b7 --- /dev/null +++ b/src/fbgui/html/continueBoot.html @@ -0,0 +1,24 @@ + + + + + + + + + + + +
+
+
+

Continue Boot

+
+
+ +
+ + + diff --git a/src/fbgui/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/src/fbgui/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 0000000..954e22d Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/src/fbgui/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png b/src/fbgui/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000..64ece57 Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/src/fbgui/html/css/images/ui-bg_flat_10_000000_40x100.png b/src/fbgui/html/css/images/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 0000000..abdc010 Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_flat_10_000000_40x100.png differ diff --git a/src/fbgui/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png b/src/fbgui/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100644 index 0000000..9b383f4 Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png differ diff --git a/src/fbgui/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png b/src/fbgui/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png new file mode 100644 index 0000000..a23baad Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png differ diff --git a/src/fbgui/html/css/images/ui-bg_glass_65_ffffff_1x400.png b/src/fbgui/html/css/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000..42ccba2 Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/src/fbgui/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png b/src/fbgui/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png new file mode 100644 index 0000000..39d5824 Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png differ diff --git a/src/fbgui/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/src/fbgui/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 0000000..f127367 Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/src/fbgui/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png b/src/fbgui/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png new file mode 100644 index 0000000..359397a Binary files /dev/null and b/src/fbgui/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png differ diff --git a/src/fbgui/html/css/images/ui-icons_222222_256x240.png b/src/fbgui/html/css/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000..b273ff1 Binary files /dev/null and b/src/fbgui/html/css/images/ui-icons_222222_256x240.png differ diff --git a/src/fbgui/html/css/images/ui-icons_228ef1_256x240.png b/src/fbgui/html/css/images/ui-icons_228ef1_256x240.png new file mode 100644 index 0000000..a641a37 Binary files /dev/null and b/src/fbgui/html/css/images/ui-icons_228ef1_256x240.png differ diff --git a/src/fbgui/html/css/images/ui-icons_ef8c08_256x240.png b/src/fbgui/html/css/images/ui-icons_ef8c08_256x240.png new file mode 100644 index 0000000..85e63e9 Binary files /dev/null and b/src/fbgui/html/css/images/ui-icons_ef8c08_256x240.png differ diff --git a/src/fbgui/html/css/images/ui-icons_ffd27a_256x240.png b/src/fbgui/html/css/images/ui-icons_ffd27a_256x240.png new file mode 100644 index 0000000..e117eff Binary files /dev/null and b/src/fbgui/html/css/images/ui-icons_ffd27a_256x240.png differ diff --git a/src/fbgui/html/css/images/ui-icons_ffffff_256x240.png b/src/fbgui/html/css/images/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000..42f8f99 Binary files /dev/null and b/src/fbgui/html/css/images/ui-icons_ffffff_256x240.png differ diff --git a/src/fbgui/html/css/jquery-ui-1.8.16.css b/src/fbgui/html/css/jquery-ui-1.8.16.css new file mode 100644 index 0000000..5547c7b --- /dev/null +++ b/src/fbgui/html/css/jquery-ui-1.8.16.css @@ -0,0 +1,568 @@ +/* + * jQuery UI CSS Framework 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* + * jQuery UI CSS Framework 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } +.ui-widget-content a { color: #333333; } +.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } +.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } +.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* + * jQuery UI Resizable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* + * jQuery UI Selectable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectable#theming + */ +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } +/* + * jQuery UI Accordion 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Accordion#theming + */ +/* IE/Win - Fix animation bug - #4615 */ +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; } +/* + * jQuery UI Autocomplete 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete#theming + */ +.ui-autocomplete { position: absolute; cursor: default; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* + * jQuery UI Menu 1.8.16 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Menu#theming + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; + float: left; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} +/* + * jQuery UI Button 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Button#theming + */ +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ +/* + * jQuery UI Dialog 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog#theming + */ +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } +.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* + * jQuery UI Slider 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* + * jQuery UI Tabs 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs#theming + */ +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } +/* + * jQuery UI Datepicker 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* + * jQuery UI Progressbar 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar#theming + */ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/src/fbgui/html/images/loading.gif b/src/fbgui/html/images/loading.gif new file mode 100644 index 0000000..cbe59fb Binary files /dev/null and b/src/fbgui/html/images/loading.gif differ diff --git a/src/fbgui/html/js/jquery-1.6.4.min.js b/src/fbgui/html/js/jquery-1.6.4.min.js new file mode 100644 index 0000000..628ed9b --- /dev/null +++ b/src/fbgui/html/js/jquery-1.6.4.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */ +(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/src/fbgui/html/js/jquery-ui-1.8.16.min.js b/src/fbgui/html/js/jquery-ui-1.8.16.min.js new file mode 100644 index 0000000..14c9064 --- /dev/null +++ b/src/fbgui/html/js/jquery-ui-1.8.16.min.js @@ -0,0 +1,791 @@ +/*! + * jQuery UI 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */ +(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.16", +keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({propAttr:c.fn.prop||c.fn.attr,_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d= +this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this, +"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart": +"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight, +outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a, +"tabindex"),d=isNaN(b);return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&& +a.element[0].parentNode)for(var e=0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= +false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); +;/* + * jQuery UI Position 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Position + */ +(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, +left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= +k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= +m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= +d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= +a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), +g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); +;/* + * jQuery UI Draggable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */ +(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== +"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= +this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;if(b.iframeFix)d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('
').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options; +this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); +this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true}, +_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b= +false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, +10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle|| +!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&& +a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= +this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"), +10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), +10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, +(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!= +"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"), +10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+ +this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&& +!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.leftg[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.topg[3])?h:!(h-this.offset.click.topg[2])?e:!(e-this.offset.click.left=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e=j&&f<=l||h>=j&&h<=l||fl)&&(e>= +i&&e<=k||g>=i&&g<=k||ek);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), +top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= +this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", +nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor== +String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection(); +this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){if(!a.disabled){e(this).removeClass("ui-resizable-autohide");b._handles.show()}},function(){if(!a.disabled)if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy(); +var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a= +false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"}); +this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff= +{width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis]; +if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false}, +_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f, +{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(b){var a=this.options,c,d,f;a={minWidth:k(a.minWidth)?a.minWidth:0,maxWidth:k(a.maxWidth)?a.maxWidth:Infinity,minHeight:k(a.minHeight)?a.minHeight:0,maxHeight:k(a.maxHeight)?a.maxHeight: +Infinity};if(this._aspectRatio||b){b=a.minHeight*this.aspectRatio;d=a.minWidth/this.aspectRatio;c=a.maxHeight*this.aspectRatio;f=a.maxWidth/this.aspectRatio;if(b>a.minWidth)a.minWidth=b;if(d>a.minHeight)a.minHeight=d;if(cb.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&l)b.left=i-a.minWidth;if(d&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left= +null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+ +a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+ +c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]); +b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.16"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(), +10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top- +f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var l=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:l.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(l.css("position"))){c._revertToRelativePosition=true;l.css({position:"absolute",top:"auto",left:"auto"})}l.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType? +e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a= +e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing, +step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement= +e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset; +var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left: +a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top- +d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition, +f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25, +display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b= +e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height= +d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery); +;/* + * jQuery UI Selectable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * jquery.ui.core.js + * jquery.ui.mouse.js + * jquery.ui.widget.js + */ +(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"), +selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("
")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX, +c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting", +c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d= +this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.righti||a.bottomb&&a.rightg&&a.bottom *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable"); +this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a=== +"disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&& +!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top, +left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]}; +this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!= +document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a); +return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0], +e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset(); +c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"): +this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null, +dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")}, +toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+jg&&b+la[this.floating?"width":"height"]?j:g0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith(); +if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), +this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b= +this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f= +d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")|| +0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out", +a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h- +f)this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g- +this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.topthis.containment[3])?g:!(g-this.offset.click.topthis.containment[2])?f:!(f-this.offset.click.left=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this, +this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop", +a,this._uiHash());for(e=0;e li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"); +a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); +if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion", +function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a= +this.options;if(a.icons){c("").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"); +this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons(); +b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target); +a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+ +c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options; +if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header); +if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(), +e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight|| +e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false", +"aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.16", +animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/); +f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide", +paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery); +;/* + * jQuery UI Autocomplete 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + * jquery.ui.position.js + */ +(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.propAttr("readOnly"))){g= +false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!= +a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)}; +this.menu=d("
    ").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&& +a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); +d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&& +b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source= +this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length").data("item.autocomplete",b).append(d("").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, +"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery); +(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", +-1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); +this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b, +this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| +this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| +this.first()?":last":":first"))},hasScroll:function(){return this.element.height()").addClass("ui-button-text").html(this.options.label).appendTo(a.empty()).text(),e=this.options.icons,f=e.primary&&e.secondary,d=[];if(e.primary||e.secondary){if(this.options.text)d.push("ui-button-text-icon"+(f?"s":e.primary?"-primary":"-secondary"));e.primary&&a.prepend("");e.secondary&&a.append("");if(!this.options.text){d.push(f?"ui-button-icons-only": +"ui-button-icon-only");this.hasTitle||a.attr("title",c)}}else d.push("ui-button-text-only");a.addClass(d.join(" "))}}});b.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(a,c){a==="disabled"&&this.buttons.button("option",a,c);b.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var a=this.element.css("direction")=== +"ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(a?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(a?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"); +b.Widget.prototype.destroy.call(this)}})})(jQuery); +;/* + * jQuery UI Dialog 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + * jquery.ui.button.js + * jquery.ui.draggable.js + * jquery.ui.mouse.js + * jquery.ui.position.js + * jquery.ui.resizable.js + */ +(function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, +position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("
    ")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ +b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&!i.isDefaultPrevented()&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("
    ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g), +h=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("").addClass("ui-dialog-title").attr("id", +e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); +a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!== +b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()};c.ui.dialog.maxZ+=1; +d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target=== +f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("
    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("
    ").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a, +function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", +handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition, +originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize", +f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "): +[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f); +if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"): +e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a= +this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height- +b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "), +create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&& +c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(b.range==="min"||b.range==="max"?" ui-slider-range-"+b.range:""))}for(var j=c.length;j"); +this.handles=c.add(d(e.join("")).appendTo(a.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle", +g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!a.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");i=a._start(g,l);if(i===false)return}break}m=a.options.step;i=a.options.values&&a.options.values.length? +(h=a.values(l)):(h=a.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=a._valueMin();break;case d.ui.keyCode.END:h=a._valueMax();break;case d.ui.keyCode.PAGE_UP:h=a._trimAlignValue(i+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=a._trimAlignValue(i-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===a._valueMax())return;h=a._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===a._valueMin())return;h=a._trimAlignValue(i- +m);break}a._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(g,k);a._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); +return this},_mouseCapture:function(a){var b=this.options,c,f,e,j,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(b.range===true&&this.values(1)===b.min){g+=1;e=d(this.handles[g])}if(this._start(a,g)===false)return false; +this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();b=e.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-e.width()/2,top:a.pageY-b.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b= +this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b= +this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b); +c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var f;if(this.options.values&&this.options.values.length){f=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>f||b===1&&c1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a= +this.options.range,b=this.options,c=this,f=!this._animateOff?b.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({width:e- +g+"%"},{queue:false,duration:b.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:b.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[f?"animate":"css"]({width:e+"%"}, +b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.16"})})(jQuery); +;/* + * jQuery UI Tabs 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ +(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
    ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
  • #{label}
  • "},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& +e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= +d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| +(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); +this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= +this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); +if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); +this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ +g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", +function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; +this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= +-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; +d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= +d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, +e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); +j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); +if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, +this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, +load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, +"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, +url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.16"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k'))}function N(a){return a.bind("mouseout", +function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); +b.addClass("ui-state-hover");b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.16"}});var B=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv}, +setDefaults:function(a){H(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g, +"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('
    '))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker", +function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b);b.settings.disabled&&this._disableDatepicker(a)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d(''+c+"");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c== +"focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('').addClass(this._triggerClass).html(f==""?c:d("").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker(): +d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;gh){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a, +b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.settings.disabled&&this._disableDatepicker(a);b.dpDiv.css("display","block")}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+= +1;this._dialogInput=d('');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/ +2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b= +d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e= +a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a, +"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f== +a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input", +a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c=d.datepicker._get(b,"beforeShow");c=c?c.apply(a,[a,b]):{};if(c!==false){H(b.settings,c);b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value= +"";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b); +c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing= +true;d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv);J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}); +a.dpDiv.find("."+this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&& +!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(), +h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b= +this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b); +this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, +_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"): +0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e["selected"+(c=="M"? +"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a); +this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField"); +if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"? +b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=A+1-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd", +COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames: +null)||this._defaults.monthNames;var i=function(o){(o=k+1 +12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&& +a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay? +new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&nn;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a)); +n=this._canAdjustMonth(a,-1,m,g)?''+n+"":f?"":''+n+"";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m, +g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?''+s+"":f?"":''+s+"";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&& +a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'":"";e=e?'
    '+(c?h:"")+(this._isInRange(a,s)?'":"")+(c?"":h)+"
    ":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),A=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='
    '+(/all|left/.test(t)&& +x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,A,v)+'
    ';var z=j?'":"";for(t=0;t<7;t++){var r=(t+h)%7;z+="=5?' class="ui-datepicker-week-end"':"")+'>'+q[r]+""}y+=z+"";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay, +z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q";var R=!j?"":'";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&ro;R+='";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+""}g++;if(g>11){g=0;m++}y+="
    '+this._get(a,"weekHeader")+"
    '+this._get(a,"calculateWeek")(r)+""+(F&&!D?" ":L?''+ +r.getDate()+"":''+r.getDate()+"")+"
    "+(l?""+(i[0]>0&&G==i[1]-1?'
    ':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'': +"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='
    ',o="";if(h||!j)o+=''+i[b]+"";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+=''+c+"";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b, +e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="
    ";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+ +(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&ba?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input? +a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c, +e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a, +"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this; +if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a== +"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.16";window["DP_jQuery_"+B]=d})(jQuery); +;/* + * jQuery UI Progressbar 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ +(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("
    ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); +this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* +this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.16"})})(jQuery); +;/* + * jQuery UI Effects 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/ + */ +jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], +16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, +a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= +a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", +"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, +0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, +211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, +d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; +f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, +[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.16",save:function(c,a){for(var b=0;b").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}), +d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement; +if(c.parent().is(".ui-effects-wrapper")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)}); +return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this, +arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/ +2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b, +d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c, +a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b, +d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ +e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); +;/* + * jQuery UI Effects Fade 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Fade + * + * Depends: + * jquery.effects.core.js + */ +(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); +;/* + * jQuery UI Effects Fold 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Fold + * + * Depends: + * jquery.effects.core.js + */ +(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], +10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); +;/* + * jQuery UI Effects Highlight 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Highlight + * + * Depends: + * jquery.effects.core.js + */ +(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& +this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); +;/* + * jQuery UI Effects Pulsate 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/Pulsate + * + * Depends: + * jquery.effects.core.js + */ +(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); +b.dequeue()})})}})(jQuery); +; \ No newline at end of file diff --git a/src/fbgui/html/js/networkDiscovery.js b/src/fbgui/html/js/networkDiscovery.js new file mode 100644 index 0000000..2aaea11 --- /dev/null +++ b/src/fbgui/html/js/networkDiscovery.js @@ -0,0 +1,278 @@ +var hideProgressIndicator = function () { + $("#ajaxBusy").hide(); +}; + + + +var updateTips = function ( t ) { + $( ".validateTips" ) + .text( t ) + .addClass( "ui-state-highlight" ); + setTimeout( + function() { + $( ".validateTips" ).removeClass( "ui-state-highlight", 1500 ); + }, + 500 ); +}; + + + +var checkLength = function ( o, n, min, max ) { + if ( o.val().length > max || o.val().length < min ) { + o.addClass( "ui-state-error" ); + updateTips( "Length of " + n + " must be between " + + min + " and " + max + "." ); + return false; + } else { + return true; + } +}; + + + +var checkRegexp = function ( o, regexp, n ) { + if ( !( regexp.test( o.val() ) ) ) { + o.addClass( "ui-state-error" ); + updateTips( n ); + return false; + } else { + return true; + } +}; + + + +var showLog = function (t) { + $("#nd_show_log_msg").html(t); + //$("#nd_show_log_msg").attr('readonly','readonly'); + $('#nd_show_log_dialog').resizable("enable"); + $("#nd_show_log_dialog").dialog( + { buttons: { "Cancel": function() { + $(this).dialog("close");}}, + minWidth: 600, + maxHeight: 400, + modal: true, + draggable: false, + closeOnEscape: false, + open: function(event, ui) { + $(this).css({'max-height': 400, 'overflow-y': 'auto'}); + }, + }); +}; + + + +var getInterfaceConfOnChange = function (i) { + var n = i.options[i.selectedIndex].text; + var jsonObj = fbgui.getInterfaceConf(n); + if (!jQuery.isEmptyObject(jsonObj)) { + $("#ipaddr").val(jsonObj.ipaddr); + $("#netmask").val(jsonObj.netmask); + $("#broadcast").val(jsonObj.broadcast); + $("#gateway").val(jsonObj.gateway); + $("#dns").val(jsonObj.dns); + } + +}; + + + +var getInterfaceConf = function (i) { + var jsonObj = fbgui.getInterfaceConf(i); + if (!jQuery.isEmptyObject(jsonObj)) { + $("#ipaddr").val(jsonObj.ipaddr); + $("#netmask").val(jsonObj.netmask); + $("#broadcast").val(jsonObj.broadcast); + $("#gateway").val(jsonObj.gateway); + $("#dns").val(jsonObj.dns); + } + +}; + + + +var ip4_manualConfigurationDialog = function () { + var jsonArr = fbgui.getManualConfInterfaces(); + if(jsonArr == "") { + var c = "

    Have not found usable interfaces for manual configuration

    "; + $("#nd_manual_configuration_dialog").html(c); + $("#nd_manual_configuration_dialog").dialog( + { buttons: { "Cancel": function() { + $(this).dialog("close");}}, + minWidth: 450, + modal: true, + resizable: false, + draggable: false, + open: function(event, ui) { $(".ui-dialog-titlebar-close").hide();} + }); + + } else { + var c = ""; + $("#nd_mc_ifname").html(c); + + var ifname = $("#nd_mc_ifname_select :selected").text(), + ipaddr = $("#ipaddr"), + netmask = $("#netmask"), + broadcast = $("#broadcast"), + gateway = $("#gateway"), + dns = $("#dns"), + allFields = $([]).add(ipaddr).add(netmask).add(broadcast).add(gateway).add(dns); + + getInterfaceConf(ifname); + + $("#nd_manual_configuration_dialog").dialog( + { buttons: { "Cancel": function() { + $(this).dialog("close");}, + "Continue": function() { + var bValid = true; + allFields.removeClass("ui-state-error"); + + bValid = bValid && checkLength(ipaddr, "IP-Address", 7, 15); + bValid = bValid && checkLength(netmask, "Netmask Address", 7, 15); + bValid = bValid && checkLength(broadcast, "Broadcast Address", 7, 15); + bValid = bValid && checkLength(gateway, "Gateway Address", 7, 15); + bValid = bValid && checkLength(dns, "DNS Address", 7, 15); + + bValid = bValid && checkRegexp(ipaddr, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 192.168.1.2 (max value is 255)"); + bValid = bValid && checkRegexp(netmask, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 255.255.255.0 (max value is 255)"); + bValid = bValid && checkRegexp(broadcast, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 192.168.1.255 (max value is 255)"); + bValid = bValid && checkRegexp(gateway, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 192.168.1.254 (max value is 255)"); + bValid = bValid && checkRegexp(dns, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 192.168.1.111 (max value is 255)"); + + if (bValid) { + // put variables into a json object + // send to qt networkdiscovery + var o = {"ifname" : ifname, + "ipaddr" : ipaddr.val(), + "netmask" : netmask.val(), + "broadcast" : broadcast.val(), + "gateway" : gateway.val(), + "dns" : dns.val() } + try { + fbgui.ip4_setManualConfiguration(o); + } catch (e) { + fbgui.notifyCall(e); + } + $(this).dialog("close"); + } } + } , + minWidth: 450, + modal: true, + resizable: false, + draggable: false, + closeOnEscape: false, + close: function() {allFields.val("").removeClass("ui-state-error");}, + open: function(event, ui) { $(".ui-dialog-titlebar-close").hide();} + }); + } +}; + + + +var abortBootDialog = function (m) { + fbgui.notifyCall("abortBootDialog"); + $("#nd_abort_boot_msg").html(m); + $("#nd_abort_boot_dialog").dialog( + { buttons: { "Manual Configure": function() { + ip4_manualConfigurationDialog();}, + "Show Log": function() { + var text = fbgui.readLogFile(); + showLog(text);}, + "Restart": function() {fbgui.restartSystem(); + $(this).dialog("close"); }, + "Shut Down": function() { fbgui.shutDownSystem(); + $(this).dialog("close"); }, + "Try Again": function() {fbgui.tryAgain(); + $(this).dialog("close"); } + } , + minWidth: 450, + modal: true, + resizable: false, + draggable: false, + closeOnEscape: false, + open: function(event, ui) { $(".ui-dialog-titlebar-close").hide();} + }); +}; + + + +var chooseInterfaceDialog = function (i) { + var cb = ""+ + ""; + + $("#nd_choose_interface_msg").html(cb); + $("#nd_choose_interface_dialog").dialog( + { buttons: { "Manual Configure": function() { + ip4_manualConfigurationDialog();}, + "Show Log": function() { + var text = fbgui.readLogFile(); + showLog(text);}, + "Restart": function() {fbgui.restartSystem(); + $(this).dialog("close"); }, + "Shut Down": function() { fbgui.shutDownSystem(); + $(this).dialog("close"); }, + "Continue": function() { + var ifName = $("#nd_ifName_select :selected").text(); + fbgui.continueBoot(ifName); + $(this).dialog("close"); + } + } , + minWidth: 550, + modal: true, + resizable: false, + draggable: false, + closeOnEscape: false, + open: function(event, ui) { $(".ui-dialog-titlebar-close").hide();} + }); +} + + + +var updateStatus = function (s){ + $("#nd_status").html(s); +}; + + + +var updateIfProgressBar = function (i, p){ + if (p >= 0 && p <= 100){ + $("#"+i+"_progress").progressbar({ value: p }); + }else{ + $("#"+i+"_progress").progressbar({ value: 0 }); + } +}; + + + +var updateIfStatus = function(i, s){ + $("#"+i+"_status").html(s); +}; + + + +var addInterface = function (i){ + hideProgressIndicator(); + $("#nd_progress_container").append( + "
    "+ + " Interface: " +i+ + " Start DHCP " + + "
    "+ + "
    " + ); + //$("#"+i+"_progress").progressbar({ value: 33 }); +}; + + diff --git a/src/fbgui/html/loadsystem.css b/src/fbgui/html/loadsystem.css new file mode 100644 index 0000000..6a6e64f --- /dev/null +++ b/src/fbgui/html/loadsystem.css @@ -0,0 +1,90 @@ +html,body{ + height:100%; +} +body{ + margin:0; + padding:0; + background-color:black; + /* + background-image:url('background.png'); + background-repeat:no-repeat; + */ + background-size:100%; +} +#message{ + position:relative; + font-size:90%; + top:40%; +} +h1, p{ + text-align:center; + color:white; +} +* html{ + height:100%; +} +/* position the bars and balls correctly (rotate them and translate them outward)*/ +.bar1 { + -moz-transform:rotate(0deg) translate(0, -40px); + -webkit-transform:rotate(0deg) translate(0, -40px);opacity:0.12; +} +.bar2 { + -moz-transform:rotate(45deg) translate(0, -40px); + -webkit-transform:rotate(45deg) translate(0, -40px);opacity:0.25; +} +.bar3 { + -moz-transform:rotate(90deg) translate(0, -40px); + -webkit-transform:rotate(90deg) translate(0, -40px);opacity:0.37; +} +.bar4 { + -moz-transform:rotate(135deg) translate(0, -40px); + -webkit-transform:rotate(135deg) translate(0, -40px);opacity:0.50; +} +.bar5 { + -moz-transform:rotate(180deg) translate(0, -40px); + -webkit-transform:rotate(180deg) translate(0, -40px);opacity:0.62; +} +.bar6 { + -moz-transform:rotate(225deg) translate(0, -40px); + -webkit-transform:rotate(225deg) translate(0, -40px);opacity:0.75; +} +.bar7 { + -moz-transform:rotate(270deg) translate(0, -40px); + -webkit-transform:rotate(270deg) translate(0, -40px);opacity:0.87; +} +.bar8 { + -moz-transform:rotate(315deg) translate(0, -40px); + -webkit-transform:rotate(315deg) translate(0, -40px);opacity:1; +} +#div4 { + position:absolute; + left:50%; + top:50%; + margin-left:-50px; + margin-top:-50px; + width:100px; + height:100px; + -moz-border-radius:100px; + -webkit-border-radius:100px; + -moz-transform:scale(0.5); + -webkit-transform:scale(0.5); + -webkit-animation-name: rotateThis; + -webkit-animation-duration:2s; + -webkit-animation-iteration-count:infinite; + -webkit-animation-timing-function:linear; +} +#div4 div { + width:20px; + height:20px; + background:#fff; + -moz-border-radius:40px; + -webkit-border-radius:40px; + position:absolute; + left:40px; + top:40px; +} +/* add a shadow to the first */ +#div4 div { + -moz-box-shadow:black 0 0 4px; + -webkit-box-shadow:black 0 0 4px; +} diff --git a/src/fbgui/html/loadsystem.html b/src/fbgui/html/loadsystem.html new file mode 100644 index 0000000..838423e --- /dev/null +++ b/src/fbgui/html/loadsystem.html @@ -0,0 +1,35 @@ + + + + + + + +
    +

    Loading system, please wait...

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + diff --git a/src/fbgui/html/networkdiscovery.css b/src/fbgui/html/networkdiscovery.css new file mode 100644 index 0000000..cf4121d --- /dev/null +++ b/src/fbgui/html/networkdiscovery.css @@ -0,0 +1,90 @@ +html,body{ + height:100%; +} + +label, input { + display:block +} + +input.text { + margin-bottom:12px; + width:95%; + padding: .4em; +} + +fieldset { + padding:0; + border:0; + margin-top:25px; +} + +.validateTips { + border:1px solid transparent; + padding: 0.3; +} + +body{ + margin:0; + padding:0; + /*background-color:blue; + /* + background-image:url('background.png'); + background-repeat:no-repeat; + */ + background-size:100%; +} + +/* Tell the browser to render HTML 5 elements as block */ +header, footer, aside { + display: block; +} + +#intro { + margin: 20px; +} + +#content { + display: table; + width: 100%; +} + +#mainContent { + display: table-cell; + width: 620px; + padding-right: 22px; + padding-left: 22px; +} + +aside { + display: table-cell; + width: 300px; +} + +#nd_manual_configuration_dialog, #nd_show_log_dialog { + display:none; +} + +#ajaxBusy { + margin-left: auto; + margin-right: auto; +} + + .ui-button-text { + font-size: 10px; +} + +textarea { + width: 400px; + height: 200px; + /*resize: none;*/ +} + +h1 { + margin-top: 20px; +} + +h1, p{ + color:#333; + text-align:center; +} + diff --git a/src/fbgui/html/networkdiscovery.html b/src/fbgui/html/networkdiscovery.html new file mode 100644 index 0000000..a1e62ac --- /dev/null +++ b/src/fbgui/html/networkdiscovery.html @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + +
    +

    Network Discovery

    +
    +
    +

    Welcome to the Network Discovery.
    +Please press F5 if you want to choose which interface to use.
    +We are now looking for usable interfaces and will go on as soon as we found one. This may take a few seconds.

    +
    +
    +
    + +
    +
    +
    + +

    +
    + +
    +
    
    +            
    + +
    +

    +

    + +
    +

    +
    + +
    +

    +

    All form fields are required.

    +
    +
    + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    RZ Uni Freiburg, 2011

    +
    + + diff --git a/src/fbgui/html/networkdiscovery_debug.html b/src/fbgui/html/networkdiscovery_debug.html new file mode 100644 index 0000000..06c1fe7 --- /dev/null +++ b/src/fbgui/html/networkdiscovery_debug.html @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + +
    +

    Network Discovery

    +
    +
    +

    Welcome to the Network Discovery.
    +Please press F5 if you want to choose which interface to use.
    +We are now looking for usable interfaces and will go on as soon as we found one. This may take a few seconds.

    +
    +
    +
    + +
    +
    +
    + +

    +
    + +
    +
    
    +            
    + +
    +

    +

    + +
    +

    +
    + +
    +

    +

    All form fields are required.

    +
    +
    + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +

    RZ Uni Freiburg, 2011

    +
    + + diff --git a/src/fbgui/html/networkdiscovery_userchoice.html b/src/fbgui/html/networkdiscovery_userchoice.html new file mode 100644 index 0000000..3625fe0 --- /dev/null +++ b/src/fbgui/html/networkdiscovery_userchoice.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + +
    +

    Network Discovery

    +
    +
    +

    Please press F5 if you want to choose which interface to use.

    +

    +
    +
    +

    RZ Uni Freiburg, 2011

    +
    + + diff --git a/src/fbgui/html/networkdiscovery_userchoice_debug.html b/src/fbgui/html/networkdiscovery_userchoice_debug.html new file mode 100644 index 0000000..88da8b4 --- /dev/null +++ b/src/fbgui/html/networkdiscovery_userchoice_debug.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + +
    +

    Network Discovery

    +
    +
    +

    Please press F5 if you want to choose which interface to use.

    +

    +
    +
    +

    RZ Uni Freiburg, 2011

    +
    + + diff --git a/src/fbgui/html/old.png b/src/fbgui/html/old.png new file mode 100644 index 0000000..84dd7b3 Binary files /dev/null and b/src/fbgui/html/old.png differ diff --git a/src/fbgui/html/preload-debug.html b/src/fbgui/html/preload-debug.html new file mode 100644 index 0000000..29d7391 --- /dev/null +++ b/src/fbgui/html/preload-debug.html @@ -0,0 +1,34 @@ + + + + + + +
    +
    +
    +

    Preboot GUI

    +

    Waiting on internet... + + +

    +
    +
    + +
    + + + diff --git a/src/fbgui/html/preload.css b/src/fbgui/html/preload.css new file mode 100644 index 0000000..e1eff68 --- /dev/null +++ b/src/fbgui/html/preload.css @@ -0,0 +1,105 @@ +html,body{ + height:100%; +} +body{ + margin:0; + padding:0; + background-color:black; + /* + background-image:url('background.png'); + background-repeat:no-repeat; + */ + background-size:100%; +} +#top{ + position:absolute; +} +#message{ + position:absolute; + top:37%; + width:100%; + font-size:90%; +} +h1, p{ + color:white; + text-align:center; +} +#container{ + min-height:100%; + margin-bottom:-50px; +} +* html #container{ + height:100%; +} +#footer-spacer{ + height:0px; +} +#footer{ + height:30px; +} +/* animation */ +/* position the bars and balls correctly (rotate them and translate them outward)*/ +.bar1 { + -moz-transform:rotate(0deg) translate(0, -40px); + -webkit-transform:rotate(0deg) translate(0, -40px);opacity:0.12; +} +.bar2 { + -moz-transform:rotate(45deg) translate(0, -40px); + -webkit-transform:rotate(45deg) translate(0, -40px);opacity:0.25; +} +.bar3 { + -moz-transform:rotate(90deg) translate(0, -40px); + -webkit-transform:rotate(90deg) translate(0, -40px);opacity:0.37; +} +.bar4 { + -moz-transform:rotate(135deg) translate(0, -40px); + -webkit-transform:rotate(135deg) translate(0, -40px);opacity:0.50; +} +.bar5 { + -moz-transform:rotate(180deg) translate(0, -40px); + -webkit-transform:rotate(180deg) translate(0, -40px);opacity:0.62; +} +.bar6 { + -moz-transform:rotate(225deg) translate(0, -40px); + -webkit-transform:rotate(225deg) translate(0, -40px);opacity:0.75; +} +.bar7 { + -moz-transform:rotate(270deg) translate(0, -40px); + -webkit-transform:rotate(270deg) translate(0, -40px);opacity:0.87; +} +.bar8 { + -moz-transform:rotate(315deg) translate(0, -40px); + -webkit-transform:rotate(315deg) translate(0, -40px);opacity:1; +} +#div4 { + position:absolute; + left:50%; + top:50%; + margin-left:-50px; + margin-top:-50px; + width:100px; + height:100px; + -moz-border-radius:100px; + -webkit-border-radius:100px; + -moz-transform:scale(0.5); + -webkit-transform:scale(0.5); + -webkit-animation-name: rotateThis; + -webkit-animation-duration:2s; + -webkit-animation-iteration-count:infinite; + -webkit-animation-timing-function:linear; +} +#div4 div { + width:20px; + height:20px; + background:#fff; + -moz-border-radius:40px; + -webkit-border-radius:40px; + position:absolute; + left:40px; + top:40px; +} +/* add a shadow to the first */ +#div4 div { + -moz-box-shadow:black 0 0 4px; + -webkit-box-shadow:black 0 0 4px; +} diff --git a/src/fbgui/html/preload.html b/src/fbgui/html/preload.html new file mode 100644 index 0000000..bc0abd9 --- /dev/null +++ b/src/fbgui/html/preload.html @@ -0,0 +1,42 @@ + + + + + + +
    +
    +
    +

    Waiting for internet...

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + + + diff --git a/src/fbgui/interfaceconfiguration.cpp b/src/fbgui/interfaceconfiguration.cpp new file mode 100644 index 0000000..3d09e52 --- /dev/null +++ b/src/fbgui/interfaceconfiguration.cpp @@ -0,0 +1,140 @@ +/** + * @class interfaceconfiguration + * + * @brief reads and stores a interface configuration. + * + * reads and stores a interface configuration. + * the config file has already to exist. It is created by the cdhcpcd client process. + * + */ + + + +#include "interfaceconfiguration.h" + +interfaceconfiguration::interfaceconfiguration() { + _tag = "[nd:InterfaceConfiguration]"; +} + +interfaceconfiguration::~interfaceconfiguration() { + // TODO Auto-generated destructor stub +} + +/** + * This method reads the configuration values out of a file. + * + * This method reads the configuration values out of a file. + * The file has to be created before by the customdhcpcd QProcess. + * (Overwrites the old values if they are already present.) + * + * @param pathToConfig + * contains the path to the configuration file. + */ +bool interfaceconfiguration::readConfigOutOfFile(QString pathToConfig) { + QFile file(pathToConfig); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << _tag << "couldn't open file:" << pathToConfig; + return false; + } + qDebug() << _tag << "read config file"; + while (!file.atEnd()) { + QString line(file.readLine()); + QStringList splitedLine = line.split("="); + QString name = splitedLine.first().trimmed(); + splitedLine.removeFirst(); + QString values = splitedLine.first().trimmed(); + values.remove(QChar('\'')); + + if (name.compare("IPADDR") == 0) { + this->ipAddress = values; + } else if (name.compare("NETMASK") == 0) { + this->netmask = values; + } else if (name.compare("NETWORK") == 0) { + this->network = values; + } else if (name.compare("BROADCAST") == 0) { + this->broadcast = values; + } else if (name.compare("ROUTES") == 0) { + this->routes = values; + } else if (name.compare("GATEWAYS") == 0) { + this->gateways = values; + this->gateway = this->gateways.split(" ").first().trimmed(); + } else if (name.compare("HOSTNAME") == 0) { + this->hostname = values; + } else if (name.compare("DNSSEARCH") == 0) { + this->dnssearch = values; + } else if (name.compare("DNSSERVERS") == 0) { + this->dnsservers = values; + } else if (name.compare("DHCPSID") == 0) { + this->dhcpsid = values; + } else if (name.compare("INTERFACE") == 0) { + this->interface = values; + } else if (name.compare("CLIENTID") == 0) { + this->clientid = values; + } else if (name.compare("DHCPCHADDR") == 0) { + this->dhcpchaddr = values; + } else { + qDebug() << _tag << "read unknown name" << name << values; + } + } + } else { + qDebug() << _tag << "file doesn't exist:" << pathToConfig; + return false; + } + return true; +} + +QString interfaceconfiguration::getBroadcast() { + return broadcast; +} + +QString interfaceconfiguration::getClientid() { + return clientid; +} + +QString interfaceconfiguration::getDhcpchaddr() { + return dhcpchaddr; +} + +QString interfaceconfiguration::getDhcpsid() { + return dhcpsid; +} +QString interfaceconfiguration::getDnssearch() { + return dnssearch; +} + +QString interfaceconfiguration::getDnsservers() { + return dnsservers; +} + +QString interfaceconfiguration::getGateways() { + return gateways; +} + +QString interfaceconfiguration::getGateway() { + return gateway; +} + +QString interfaceconfiguration::getHostname() { + return hostname; +} + +QString interfaceconfiguration::getInterface() { + return interface; +} + +QString interfaceconfiguration::getIpAddress() { + return ipAddress; +} + +QString interfaceconfiguration::getNetmask() { + return netmask; +} + +QString interfaceconfiguration::getNetwork() { + return network; +} + +QString interfaceconfiguration::getRoutes() { + return routes; +} diff --git a/src/fbgui/interfaceconfiguration.h b/src/fbgui/interfaceconfiguration.h new file mode 100644 index 0000000..475f689 --- /dev/null +++ b/src/fbgui/interfaceconfiguration.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + */ + + + +#ifndef INTERFACECONFIGURATION_H_ +#define INTERFACECONFIGURATION_H_ + +#include + +class interfaceconfiguration: public QObject { +Q_OBJECT + +public: + interfaceconfiguration(); + interfaceconfiguration(const interfaceconfiguration &other); + + interfaceconfiguration &operator=(const interfaceconfiguration &other); + virtual ~interfaceconfiguration(); + + bool readConfigOutOfFile(QString pathToConfig); + QString getBroadcast(); + QString getClientid(); + QString getDhcpchaddr(); + QString getDhcpsid(); + QString getDnssearch(); + QString getDnsservers(); + QString getGateways(); + QString getGateway(); + QString getHostname(); + QString getInterface(); + QString getIpAddress(); + QString getNetmask(); + QString getNetwork(); + QString getRoutes(); + +private: + QString _tag; + + QString ipAddress; + QString netmask; + QString network; + QString broadcast; + QString routes; + QString gateway; + QString gateways; + QString hostname; + QString dnssearch; + QString dnsservers; + QString dhcpsid; + QString interface; + QString clientid; + QString dhcpchaddr; +}; + +#endif /* INTERFACECONFIGURATION_H_ */ diff --git a/src/fbgui/javascriptinterface.cpp b/src/fbgui/javascriptinterface.cpp new file mode 100644 index 0000000..b45a2f9 --- /dev/null +++ b/src/fbgui/javascriptinterface.cpp @@ -0,0 +1,235 @@ +#include "fbgui.h" +#include "javascriptinterface.h" +#include "sysinfo.h" + +//------------------------------------------------------------------------------------------------------- +// Initialisation +//------------------------------------------------------------------------------------------------------- +/** + * A constructor. + * + * @param parent + * Is of type QWebFrame. + */ +JavascriptInterface::JavascriptInterface(QWebFrame *parent) { + qxtLog->debug() << "Initializing javascript interface..."; + _parent = parent; +} +//------------------------------------------------------------------------------------------------------- +/** + * An empty destructor. + */ +JavascriptInterface::~JavascriptInterface() { /* destructor dummy */ +} +//------------------------------------------------------------------------------------------------------- +/** + * Attaches an instance of this class to the DOM of the HTML page. + * + * Attaches an instance of this class to the DOM of the HTML page. + * This enables the possibility to call slots/methods of this class in + * JavaScript functions of HTML page. It also calls the + * JavascriptInterface::loadJQuery() method. + * + * @see JavascriptInterface::loadJQuery() + */ +void JavascriptInterface::attachToDOM() { + _parent->addToJavaScriptWindowObject(QString("fbgui"), this); + loadJQuery(); +} +//------------------------------------------------------------------------------------------------------- +/** + * This method load the required jQuery libraries into the HTML page. + * + * This method load the required jQuery libraries into the HTML page. + * The libraries are contained in the fbgui.qrc file. + * The Path to the files is: ":/html/js". + * Each library will be read and loaded into the HTML page via + * the evaluateJavaScript() method. + * + * @see JavascriptInterface::attachToDOM() + */ +void JavascriptInterface::loadJQuery() { + // to test if this actually works... + QString js; + QString pathToJsDir(DEFAULT_QRC_HTML_DIR); + pathToJsDir.append("/js"); + + QDir qrcJSDir(pathToJsDir); + QFileInfoList fiList = qrcJSDir.entryInfoList(); + QFileInfo fi; +foreach(fi, fiList) +{ + if (fi.suffix() == "js") { + //qDebug()<< fi.fileName(); + //qxtLog->debug() << fi.fileName(); + if (fi.fileName() != "test.js") { + QFile file; + file.setFileName(pathToJsDir + "/" + fi.fileName()); + file.open(QIODevice::ReadOnly); + js = file.readAll(); + file.close(); + + _parent->evaluateJavaScript(js); + //qxtLog->debug() << "evaluated " + fi.fileName(); + } + } +} +} +//------------------------------------------------------------------------------------------------------- +// Javascript functions for webpage +//------------------------------------------------------------------------------------------------------- +/** + * This method start a download. + * + * This method start a download. + * Can be called from inside a JavaScript function of the HTML page. + * Emits the JavascriptInterface::requestFile(const QString) signal. + */ +void JavascriptInterface::startDownload(const QString& filename) { + // ignore if empty filename + if (filename.isEmpty()) { + _parent->evaluateJavaScript("alert(\"No filename!\")"); + return; + } + emit requestFile(filename); +} +//------------------------------------------------------------------------------------------------------- +/** + * This method start a download. + * + * This method start a download. + * Can be called from inside a JavaScript function of the HTML page. + * + * @todo add some more informations + */ +void JavascriptInterface::setCallbackOnFinished(const QString& function) { + qxtLog->debug() << "[jsi] Callback set: " << function; + _callbackOnDownloadsFinished = QString(function); +} +//------------------------------------------------------------------------------------------------------- +/** + * This method delivers system informations. + * + * This method delivers system informations. Type of informations, are defined by + * the parameter. The output of this method depends on the parameter. + * Can be called from inside a JavaScript function of the HTML page. + * + * @param infoName + * Is of type QString. Defines which method will be called. Possible values are: + * - mac + * - ip + * - mbserial + * - usb + * + * @return QString + * the output of the called method or "info_error" if an error occurred + * (e. g. invalid parameter). + * + * @see SysInfo::getInfo(const QString& infoName) + */ +const QString JavascriptInterface::getSysInfo(const QString& info) { + SysInfo si; + return si.getInfo(info); +} +//------------------------------------------------------------------------------------------------------- +/** + * This method quits the whole program. + * + * This method quits the whole program. + * Can be called from inside a JavaScript function of the HTML page. + * Emits JavascriptInterface::quitFbgui() signal + */ +void JavascriptInterface::quit() { + emit quitFbgui(); +} + +//------------------------------------------------------------------------------------------------------- +/** + * This method performs a shutdown of the client. + * + * This method performs a shutdown of the client. + * Emits the JavascriptInterface::shutDownClient() signal.It is + * connected with the fbgui::performShutDown() method. + * + * @see fbgui::performShutDown() + */ +void JavascriptInterface::shutDown() { + emit shutDownClient(); +} +//------------------------------------------------------------------------------------------------------- +/** + * This method performs a reboot of the client. + * + * This method performs a reboot of the client. + * Emits the JavascriptInterface::rebootClient() signal. It is + * connected with the fbgui::performReboot() method. + * + * @see fbgui::performReboot() + */ +void JavascriptInterface::reboot() { + emit rebootClient(); +} +//------------------------------------------------------------------------------------------------------- +// Download Manager information exchange +//------------------------------------------------------------------------------------------------------- +/** + * This method delivers some informations about the downloading file. + * + * This method delivers some informations about the downloading file. + * + * @todo add some more informations + */ +void JavascriptInterface::downloadInfo(const QString& filename, + const double& filesize) { + QString code = QString("downloadInfo('\%1', \%2)").arg(filename).arg( + filesize); + _parent->evaluateJavaScript(code); +} +//------------------------------------------------------------------------------------------------------- +/** + * This method updates the progress bar. + * + * This method calls a Javascript function to update the progress bar of the download. + * Javascript must have a function called "updateProgress" to receive this information. + * + * @todo add some more informations + */ +void JavascriptInterface::updateProgressBar(const int& percent, + const double& speed, const QString& unit) { + if (percent == 0) + return; + QString code = QString("updateProgress(\%1, \%2, '\%3')").arg(percent).arg( + speed).arg(unit); + _parent->evaluateJavaScript(code); +} +//------------------------------------------------------------------------------------------------------- +/** + * This method sends out messages to Javascript. A corresponding function must be implemented + * on the webpage to receive these. + */ +void JavascriptInterface::notify(const QString& msg) { + qxtLog->debug() << "[jsi] Notifying: " << msg; + QString code = QString("notify('\%1')").arg(msg); + _parent->evaluateJavaScript(code); +} +//------------------------------------------------------------------------------------------------------- +/** + * Sets a callback function for when downloads are finished (will be called when the queue is empty). + */ +void JavascriptInterface::callbackOnFinished() { + QString code = QString("\%1").arg(_callbackOnDownloadsFinished); + _parent->evaluateJavaScript(code); +} +//------------------------------------------------------------------------------------------------------- +/** + * This method triggers the URL load *FOR DEBUGGING/TESTING PURPOSES* + + */ +void JavascriptInterface::trigger() { + QFile file(fileToTriggerURL); + if (file.open(QIODevice::WriteOnly)) { + file.write("data\n"); + qxtLog->debug() << "[jsi] *trigger watcher*"; + } + file.close(); +} diff --git a/src/fbgui/javascriptinterface.h b/src/fbgui/javascriptinterface.h new file mode 100644 index 0000000..cf2ec5b --- /dev/null +++ b/src/fbgui/javascriptinterface.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + * + * + * Interface for javascript. + * + */ + +#ifndef JAVASCRIPTINTERFACE_H_ +#define JAVASCRIPTINTERFACE_H_ + +#include "fbgui.h" + +class JavascriptInterface: public QObject { +Q_OBJECT +public: + JavascriptInterface(QWebFrame* parent); + ~JavascriptInterface(); + +private: + // pointer to parent + QWebFrame* _parent; + // function to be called withint javascript when downloads are done. + QString _callbackOnDownloadsFinished; + // loads jQuery code + void loadJQuery(); + + signals: + // request the file from download manager + void requestFile(const QString& filename); + // quit the application + void quitFbgui(); + // shut off the system. connected to fbgui::performShutDown() + void shutDownClient(); + // reboot the system. connected to fbgui::performReboot() + void rebootClient(); + +public slots: + // make sure the interface stays attached on webpage reload + void attachToDOM(); + + // slots for calling from the webpage + void startDownload(const QString& filename); + void setCallbackOnFinished(const QString& function); + const QString getSysInfo(const QString& info); + void quit(); + void shutDown(); + void reboot(); + + // callback when downloads are done. + void callbackOnFinished(); + + // slots for information exchange with the download manager. + void updateProgressBar(const int& percent, const double& speed, + const QString& unit); + void downloadInfo(const QString& filename, const double& filesize); + void notify(const QString& msg); + + // functions to help test functionality + void trigger(); +}; + +#endif // JAVASCRIPTINTERFACE_H_ diff --git a/src/fbgui/loggerengine.cpp b/src/fbgui/loggerengine.cpp new file mode 100644 index 0000000..8a0991d --- /dev/null +++ b/src/fbgui/loggerengine.cpp @@ -0,0 +1,116 @@ +#include "loggerengine.h" + +// -------------------------------------------------------------------------------------------------- +// base of a custom logger engine for the framebuffer +//--------------------------------------------------------------------------------------------------- +LoggerEngine_fb::LoggerEngine_fb(QTextEdit *parent) : + QxtLoggerEngine() { + _debugConsole = parent; + //_initialized = false; + //setLogLevelsEnabled(QxtLogger::DebugLevel); + //enableLogging(); +} +LoggerEngine_fb::~LoggerEngine_fb() { +} + +void LoggerEngine_fb::initLoggerEngine() { + //_initialized = true; + return; +} + +void LoggerEngine_fb::killLoggerEngine() { + return; +} + +void LoggerEngine_fb::setLogLevelEnabled(QxtLogger::LogLevels, bool) { + //QxtLoggerEngine::setLogLevelsEnabled(level, enable); + //if (!enable) QxtLoggerEngine::setLogLevelsEnabled(QxtLogger::DebugLevel); +} +bool LoggerEngine_fb::isInitialized() const { + //return _initialized; + return true; +} + +void LoggerEngine_fb::writeFormatted(QxtLogger::LogLevel level, const QList & msgs) { + + // ignore in case no messages was passed. + if (msgs.isEmpty()) + return; + + // write timestamp header in format: [hh:mm:ss.zzz] + // example: [23:58:99.999] + QString header = '[' + QTime::currentTime().toString("hh:mm:ss.zzz") + "] "; + _debugConsole->insertPlainText(header); + + // only write to console for debug level + if (level == QxtLogger::DebugLevel) { + Q_FOREACH(const QVariant& out, msgs) + { + if (!out.isNull()) + _debugConsole->insertPlainText(out.toString()); + } + _debugConsole->insertPlainText(QString("\n")); + // autoscroll + QTextCursor c = _debugConsole->textCursor(); + c.movePosition(QTextCursor::End); + _debugConsole->setTextCursor(c); + } +} +//--------------------------------------------------------------------------------------------------- +// slighty modified QxtBasicSTDLoggerEngine +//--------------------------------------------------------------------------------------------------- +LoggerEngine_std::LoggerEngine_std() : + QxtBasicSTDLoggerEngine() { +} + +LoggerEngine_std::~LoggerEngine_std() { +} + +void LoggerEngine_std::writeToStdErr(const QString&, const QList &msgs) { + + if (msgs.isEmpty()) + return; + QString header = '[' + QTime::currentTime().toString("hh:mm:ss.zzz") + "] "; + QTextStream* errstream = stdErrStream(); + Q_ASSERT(errstream); + *errstream << header; + Q_FOREACH(const QVariant& out, msgs) + { + if (!out.isNull()) + *errstream << out.toString(); + } + *errstream << endl; +} +void LoggerEngine_std::writeToStdOut(const QString&, const QList &) { + // (level, msgs) + // reimplementing this is needed for compiling, + // we only need write to std::err, so this function is not needed +} +//--------------------------------------------------------------------------------------------------- +// slighty modified QxtBasicFileLoggerEngine +//--------------------------------------------------------------------------------------------------- +LoggerEngine_file::LoggerEngine_file(const QString& logFileName) : + QxtBasicFileLoggerEngine(logFileName) { + //setLogFileName(logFileName); +} + +LoggerEngine_file::~LoggerEngine_file() { +} + +void LoggerEngine_file::initLoggerEngine() { +} + +void LoggerEngine_file::writeToFile(const QString&, const QList &msgs) { + + if (msgs.isEmpty()) + return; + QIODevice* file = device(); + QString header = '[' + QTime::currentTime().toString("hh:mm:ss.zzz") + "] "; + file->write(header.toUtf8()); + Q_FOREACH(const QVariant& out, msgs) + { + if (!out.isNull()) + file->write(out.toString().toUtf8()); + } + file->write("\n"); +} diff --git a/src/fbgui/loggerengine.h b/src/fbgui/loggerengine.h new file mode 100644 index 0000000..1dfae4e --- /dev/null +++ b/src/fbgui/loggerengine.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + * + * + * Base for custom logger engines based on QxtLogger libs. + * + */ +#ifndef LOGGERENGINE_H_ +#define LOGGERENGINE_H_ + +#include +#include +#include + +//--------------------------------------------------------------------------------------------------- +// base of a custom logger engine for the framebuffer +//--------------------------------------------------------------------------------------------------- +class LoggerEngine_fb: public QxtLoggerEngine { +public: + LoggerEngine_fb(QTextEdit* parent); + ~LoggerEngine_fb(); + + // parent widget, target of messages + QTextEdit *_debugConsole; + bool _initialized; + + // reimplemented virtual functions of QxtLoggerEngine + void initLoggerEngine(); + void killLoggerEngine(); + void writeFormatted(QxtLogger::LogLevel level, const QList & messages); + void setLogLevelEnabled(QxtLogger::LogLevels level, bool enable = true); + bool isInitialized() const; + +}; +//--------------------------------------------------------------------------------------------------- +// slighty modified QxtBasicSTDLoggerEngine +//--------------------------------------------------------------------------------------------------- +class LoggerEngine_std: public QxtBasicSTDLoggerEngine { +public: + LoggerEngine_std(); + ~LoggerEngine_std(); + + // reimplemented virtual functions of QxtBasicSTDLoggerEngine + void writeToStdOut(const QString& level, const QList &msgs); + void writeToStdErr(const QString& str_level, const QList &msgs); +}; +//--------------------------------------------------------------------------------------------------- +// slighty modified QxtBasicFileLoggerEngine +//--------------------------------------------------------------------------------------------------- +class LoggerEngine_file: public QxtBasicFileLoggerEngine { +public: + LoggerEngine_file(const QString& logFileName); + ~LoggerEngine_file(); + void initLoggerEngine(); + + // reimplemented virtual functions of QxtBasicFileLoggerEngine + void writeToFile(const QString& level, const QList &msgs); +}; + +#endif // LOGGERENGINE_H_ diff --git a/src/fbgui/main.cpp b/src/fbgui/main.cpp new file mode 100644 index 0000000..a187d01 --- /dev/null +++ b/src/fbgui/main.cpp @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include +#include "loggerengine.h" +#include "fbgui.h" +#include "ndgui.h" + +#include "../common/fbgui.h" + +void printHelp() { + QTextStream qout(stdout); + qout << QObject::tr("Usage: ./fbgui [OPTIONS]") << endl; + qout << QObject::tr("Options:") << endl; + qout << "-c , --config= " << QObject::tr("Path to configuration file.") << endl; + qout << "-u , --url= " << QObject::tr("Sets the URL to be loaded.") << endl; + qout << "-d , --download= " << QObject::tr("Specify the download directory.") + << endl; + qout << "-t " << QObject::tr( + "Specify location of the file triggering the URL load.") << endl; + qout << "-s " << QObject::tr( + "Specify location of the file containing the serial number.") << endl; + qout << "-D , --debug= " << QObject::tr("Activate debug mode. [0,1]") << endl; + qout << "-h, --help " << QObject::tr("Prints this help.") << endl; + qout.flush(); + exit( EXIT_SUCCESS); +} + +int main(int argc, char *argv[]) { + // Initialisation of the QApplication: + // In QT, every application is composed of two separate + // components: the GUI-Client and the GUI-Server. + // + // The third parameter sets the application as the + // GUI-Server (aswell as the GUI-Client). + + QApplication app(argc, argv, QApplication::GuiServer); + app.setOrganizationName("team_projekt_2011"); + app.setApplicationName("prebootGUI"); + binPath = QApplication::applicationDirPath(); + + QTranslator translator; + translator.load(":" + QLocale::system().name()); + app.installTranslator(&translator); + + // parse command line arguments using getopt + QMap clOpts; + int longIndex = 0; + static const char *optString = "c:u:d:s:t:D:hl:"; + static const struct option longOpts[] = { { "config", required_argument, NULL, 'c' }, { "url", + required_argument, NULL, 'u' }, { "download", required_argument, NULL, 'd' }, { "serial", + required_argument, NULL, 's' }, { "trigger", required_argument, NULL, 't' }, { "debug", + required_argument, NULL, 'D' }, { "help", no_argument, NULL, 'h' }, { "log", + required_argument, NULL, 'l' }, + { "server", required_argument, NULL, 'S' }, + { "autoup", no_argument, NULL, 'a' }, + { "socketserverpath", required_argument, NULL, 'p' }, + { "pathtoexe", required_argument, NULL, 'e' } + }; + int opt = getopt_long(argc, argv, optString, longOpts, &longIndex); + while (opt != -1) { + switch (opt) { + case 'c': + clOpts.insert("configFile", optarg); + break; + case 'l': + clOpts.insert("logFile", optarg); + break; + case 'u': + clOpts.insert("url", optarg); + break; + case 'd': + clOpts.insert("downloadDir", optarg); + break; + case 's': + clOpts.insert("serialLocation", optarg); + break; + case 't': + clOpts.insert("trigger", optarg); + break; + case 'D': + clOpts.insert("debug", optarg); + break; + case 'h': + clOpts.insert("help", "help"); + break; + case 'S': + clOpts.insert("server", optarg); + break; + case 'a': + clOpts.insert("autoup", "autoup"); + break; + case 'p': + clOpts.insert("socketserverpath", optarg); + break; + case 'e': + clOpts.insert("pathtoexe", optarg); + break; + } + opt = getopt_long(argc, argv, optString, longOpts, &longIndex); + } + + if (clOpts.contains("help")) + printHelp(); + + if (clOpts.contains("debug")) { + debugMode = clOpts.value("debug").toInt(); + // start basic debug output on terminal + qxtLog->disableLoggerEngine("DEFAULT"); + qxtLog->enableLogLevels(QxtLogger::DebugLevel); + qxtLog->addLoggerEngine("std_logger", new LoggerEngine_std); + qxtLog->initLoggerEngine("std_logger"); + qxtLog->setMinimumLevel("std_logger", QxtLogger::DebugLevel); + } else + debugMode = -1; + + // look for config file either in: + // - the path found in the configuration file + // - the user's home directory (as .fbgui.conf) + // - /etc/fbgui.conf + + QString configFilePath; + QFileInfo confInfo; + if (clOpts.contains("configFile")) + configFilePath = clOpts.value("configFile"); + else { + confInfo = QFileInfo(QDir::home(), ".fbgui.conf"); + if (confInfo.exists()) + configFilePath = confInfo.absoluteFilePath(); + else { + confInfo = QFileInfo(QString("/etc/fbgui.conf")); + if (confInfo.exists()) + configFilePath = QString("/etc/fbgui.conf"); + else + configFilePath = DEFAULT_CONFIG_PATH; + } + } + + // read the config file + QSettings confFileSettings(configFilePath, QSettings::IniFormat); + confFileSettings.setIniCodec("UTF-8"); + + // set base URL to be loaded + if (clOpts.contains("url")) + baseURL = QUrl(clOpts.value("url")); + else if (confFileSettings.contains("default/pbs_url")) + baseURL = confFileSettings.value("default/pbs_url").toUrl(); + else + baseURL = DEFAULT_URL; + + // set directory for downloads + if (clOpts.contains("downloadDir")) + downloadPath = clOpts.value("downloadDir"); + else if (confFileSettings.contains("default/download_directory")) + downloadPath = confFileSettings.value("default/download_directory").toString(); + else + downloadPath = DEFAULT_DOWNLOAD_DIR; + + // set update interval for download progress functions of download manager. + if (confFileSettings.contains("default/update_interval")) + updateInterval = confFileSettings.value("default/update_interval").toInt(); + else + updateInterval = DEFAULT_UPDATE_INTERVAL; + + // set which file to watch to trigger loading of URL + if (clOpts.contains("trigger")) + fileToTriggerURL = clOpts.value("trigger"); + else if (confFileSettings.contains("default/file_trigger")) + fileToTriggerURL = confFileSettings.value("default/file_trigger").toString(); + else + fileToTriggerURL = DEFAULT_FILE_TRIGGER; + + // set serial location + if (clOpts.contains("serialLocation")) + serialLocation = clOpts.value("serialLocation"); + else if (confFileSettings.contains("default/serial_location")) + serialLocation = confFileSettings.value("default/serial_location").toString(); + else + serialLocation = QString("/serial"); // tests + + // save ip config location (file generated by uchpc) + if (confFileSettings.contains("default/ip_config")) + ipConfigFilePath = confFileSettings.value("default/ip_config").toString(); + + // save path to log file + if (clOpts.contains("logFile")) + logFilePath = clOpts.value("logFile"); + else if (confFileSettings.contains("default/log_file")) + logFilePath = confFileSettings.value("default/log_file").toString(); + else + logFilePath = DEFAULT_LOG_FILE_PATH; + + // + if (clOpts.contains("server")) + gServerIp = clOpts.value("server"); + else if (confFileSettings.contains("default/server")) + gServerIp = confFileSettings.value("default/server").toString(); + else + gServerIp = "209.85.148.105"; //that is a google server. change this to a proper default address + + // + if (clOpts.contains("autoup")) + gAutoUp = true; + else if (confFileSettings.contains("default/autoup")) + gAutoUp = confFileSettings.value("default/autoup").toBool(); + else + gAutoUp = false; + + // + if (clOpts.contains("socketserverpath")) + gSocketServerPath = clOpts.value("socketserverpath"); + else if (confFileSettings.contains("default/socketserverpath")) + gSocketServerPath = confFileSettings.value("default/socketserverpath").toString(); + else + gSocketServerPath = DEFAULT_QTSOCKETADDRESS; + + // + if (clOpts.contains("pathtoexe")) + gPathToDhcpExe = clOpts.value("pathtoexe"); + else if (confFileSettings.contains("default/pathtoexe")) + gPathToDhcpExe = confFileSettings.value("default/pathtoexe").toString(); + else + gPathToDhcpExe = DEFAULT_PATHTODHCPCDEXE; + + + + // write always a log file + // // activate file logger if debug mode activated. + // if (debugMode > -1) { + // start debug logging to file. + qxtLog->addLoggerEngine("file_logger", new LoggerEngine_file(logFilePath)); + qxtLog->setMinimumLevel("file_logger", QxtLogger::DebugLevel); + // } + + // print config + qxtLog->debug() << "************* CONFIG INFO *************"; + qxtLog->debug() << "configFilePath: " << configFilePath.toUtf8(); + qxtLog->debug() << "logFilePath: " << logFilePath.toUtf8(); + qxtLog->debug() << "ipConfigFilePath: " << ipConfigFilePath.toUtf8(); + qxtLog->debug() << "baseURL: " << baseURL.toString().toUtf8(); + qxtLog->debug() << "downloadDir : " << downloadPath.toUtf8(); + qxtLog->debug() << "trigger: " << fileToTriggerURL.toUtf8(); + qxtLog->debug() << "serialLocation: " << serialLocation.toUtf8(); + qxtLog->debug() << "server: " << gServerIp.toUtf8(); + qxtLog->debug() << "autoup: " << gAutoUp; + qxtLog->debug() << "socketserverpath: " << gSocketServerPath.toUtf8(); + qxtLog->debug() << "pathtoexe: " << gPathToDhcpExe.toUtf8(); + qxtLog->debug() << "*******************************************"; + + // set invisible cursor + //QWSServer::instance()->setCursorVisible(false); + + // set default keyboard / mouse drivers. TODO: fix this, doesn't work... + //QWSServer::instance()->setDefaultKeyboard("TTY:/dev/tty0"); + //QWSServer::instance()->setDefaultMouse("IntelliMouse:/dev/mice"); + + + // start ndgui + qxtLog->debug() << "Initializing ndgui..."; + ndgui ngui; + fbgui gui; + + QObject::connect(&ngui, SIGNAL(initFbgui()), &gui, SLOT(init())); + ngui.show(); + return app.exec(); +} diff --git a/src/fbgui/ndgui.cpp b/src/fbgui/ndgui.cpp new file mode 100644 index 0000000..3034051 --- /dev/null +++ b/src/fbgui/ndgui.cpp @@ -0,0 +1,588 @@ +/** + * @class ndgui + * + * @brief the GUI. + * + * This class is responsible for creating and displaying the user interface. + * It also connects the webView via QWebBridge to javascript functions inside the html files. + */ + + + +#include "ndgui.h" + +QString gServerIp(""); +bool gAutoUp = true; +QString gSocketServerPath(""); +QString gPathToDhcpExe(""); + + + +/** + * constructor + */ +ndgui::ndgui(QMainWindow *parent) : + QMainWindow(parent) { + init(); +} + + + +/** + * destructor + */ +ndgui::~ndgui() { + delete _debugConsole; + delete _toggleDebugConsole; + delete _allowUserChoice; + delete _tryAgain; + delete _webView; + delete _networkDiscovery; +} + + + +/** + * @brief initialize all variables and prepare everything for a successful run + */ +void ndgui::init() { + _tag = "[nd:ndgui]"; + + _started = false; + _userChoice = false; + _ifNameList.clear(); + _manConfList.clear(); + + setupLayout(); + createAction(); + + _networkDiscovery = new NetworkDiscovery(); + connect(_networkDiscovery, SIGNAL(addInterface(const QString &)), this, + SLOT(addInterface( const QString &))); + connect(_networkDiscovery, + SIGNAL(changeProgressBarValue(const QString & , const int& )), + this, SLOT(updateIfProgressBar(const QString & , const int&))); + connect(_networkDiscovery, SIGNAL(connectionEstablished(QString)), this, + SLOT(handleConnectionEstablished(QString))); + connect(_networkDiscovery, SIGNAL(abortBoot(QString)), this, + SLOT(abortBoot(const QString))); + connect(_networkDiscovery, SIGNAL(updateIfStatus(QString,QString)), this, + SLOT(updateIfStatus(const QString &, const QString &))); + connect(_networkDiscovery, SIGNAL(updateStatus(QString)), this, + SLOT(updateStatus(const QString&))); + connect(_networkDiscovery, SIGNAL(allProcessesFinished()), this, + SLOT(handleAllProcessesFinished())); + connect(_networkDiscovery, SIGNAL(continueBoot(QString)), this, + SLOT(continueBoot(QString))); + connect(_networkDiscovery, SIGNAL(continueBootWithoutCheck(QString )), + this, SLOT(continueBootWithoutCheck(QString))); + + connect(_webView->page()->mainFrame(), SIGNAL( + javaScriptWindowObjectCleared()), this, SLOT(attachToDOM())); + connect(_webView, SIGNAL(loadFinished(bool)), this, SLOT(startSingleShot())); + + setWindowTitle(tr("NetD")); + setAttribute(Qt::WA_QuitOnClose, true); + setWindowFlags(Qt::FramelessWindowHint); + showFullScreen(); + + if (debugMode > -1) { + _webView->load(QUrl("qrc:html/networkdiscovery_debug.html")); + } else { + _webView->load(QUrl("qrc:html/networkdiscovery.html")); + + } + + _webView->show(); +} + + + +/** + * @brief This method sets the used Layout. + * + * This method sets the used Layout. Possible layout are: + * - browser mode: only the browser is visible + * - debug mode: the screen is divided into the browser and a debug + * out console + */ +void ndgui::setupLayout() { + // setup layout of the gui: debug split or browser + _webView = new QWebView(this); + _webView->setContextMenuPolicy(Qt::NoContextMenu); // if this does not work try Qt::CustomContextMenu + + if (debugMode == 1) { + // split main window in browser & debug console + createDebugConsole(); + _splitter = new QSplitter(Qt::Vertical, this); + _splitter->addWidget(_webView); + _splitter->addWidget(_debugConsole); + setCentralWidget(_splitter); + } else { + _webView->page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); + setCentralWidget(_webView); + } +} + + + +/** + * @brief This method creates a debug console as a widget. + * + * It is basicly a QTextEdit widget as provided by QT's Framework. + * An action to toggle this widget is implemented (CTRL + D). + * + * @see fbgui::toggleDebugConsole() + */ +void ndgui::createDebugConsole() { + // create the debug console widget + _debugConsole = new QTextEdit(this); + _debugConsole->setWindowFlags(Qt::FramelessWindowHint); + // fanciness + QPalette pal; + pal.setColor(QPalette::Base, Qt::black); + _debugConsole->setPalette(pal); + _debugConsole->setTextColor(Qt::white); + // enable custom logger engine + qxtLog->addLoggerEngine("fb_logger", new LoggerEngine_fb(_debugConsole)); + //qxtLog->initLoggerEngine("fb_logger"); + qxtLog->setMinimumLevel("fb_logger", QxtLogger::DebugLevel); + // CTRL + D toggles debug window + _toggleDebugConsole = new QAction(tr("&toggleDebug"), this); + _toggleDebugConsole->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); + addAction(_toggleDebugConsole); + connect(_toggleDebugConsole, SIGNAL(triggered()), this, SLOT( + toggleDebugConsole())); +} + + + +/** + * @brief This method toggles the debug console. + * + * Toggle the visibility of the debug console if the action _toggleDebugConsole is triggered. + * + * @see fbgui::createDebugConsole() + */ +void ndgui::toggleDebugConsole() { + (_debugConsole->isVisible()) ? _debugConsole->hide() : _debugConsole->show(); +} + + + +/** + * @brief Create actions + * + * creates an action which you can trigger with the F5 and F9 Button. + */ +void ndgui::createAction() { + _allowUserChoice = new QAction(tr("&userChoice"), this); + _allowUserChoice->setShortcut(QKeySequence(Qt::Key_F5)); + connect(_allowUserChoice, SIGNAL(triggered()), this, SLOT(setUserChoiceTrue())); + this->addAction(_allowUserChoice); + _tryAgain = new QAction(tr("&tryAgain"), this); + _tryAgain->setShortcut(QKeySequence(Qt::Key_F9)); + connect(_tryAgain, SIGNAL(triggered()), this, SLOT(tryAgain())); + this->addAction(_tryAgain); +} + + + +/** + * @brief set userChoice true + * + * is the connected to the triggered action pressing the F5 button. + * set the _userChoice member true + */ +void ndgui::setUserChoiceTrue() { + _userChoice = true; +} + + + +/** + * @brief starts a singleshot event. + * + * is connected to the singleShot event. Triggering this method means + * that we go on with the main NetworkDiscovery screen. + * connects the loadFinished signal of the _webView with the + * startNetworkDiscovery slot and removes the + * action. + */ +void ndgui::startSingleShot() { + + qxtLog->debug() << _tag << "start singel shot"; + QTimer::singleShot(3000, this, SLOT(startNetworkDiscovery())); +} + + + +/** + * @brief start the network discovery + * + * main starting point of the whole procedure. + * disconnect the loadFinished signal with the startNetworkDiscovery + * and starts the networkDiscovery. + */ +void ndgui::startNetworkDiscovery() { + disconnect(_webView, SIGNAL(loadFinished(bool)), this, + SLOT(startSingleShot())); + if (!_started) { + _started = true; + _networkDiscovery->initAndRun(gServerIp, _userChoice, gAutoUp, + logFilePath, gSocketServerPath, gPathToDhcpExe); + } else { + qxtLog->debug() << _tag << "NetworkDiscovery already started"; + } +} + + + +/** + * @brief handle if a interface is able to connect + * + * if we have a user choice (_userChoice = true) than networkDiscovery will + * emit connectionEstablished signals. + * Add the interface name to a _ifNameList. This list holds all interfaces + * the user can choose out of. + */ +void ndgui::handleConnectionEstablished(QString ifName) { + _ifNameList.append(ifName); +} + + + +/** + * @brief determines if we continue the boot sequence or if we show the chooseInterface or abortBoot dialog + * + * if we have a user choice (_userChoice = true) than networkDiscovery will + * emit a allProcessesFinished signal if all processes are done. + * This method determines if user will see an abort boot dialog (no interface names in + * the ifNameList list) or an + * choose interface dialog (one or more interface names in the list (add with + * handleConnectionEstablished)). + */ +void ndgui::handleAllProcessesFinished() { + qxtLog->debug() << _tag << "all Processes finished"; + _allowUserChoice->setEnabled(false); + if (_ifNameList.size() > 0) { + if (_userChoice) { + QString jsonArr = "["; + for (int i = 0; i < _ifNameList.size() - 1; i++) { + jsonArr += "\"" + _ifNameList.value(i) + "\","; + } + jsonArr += "\"" + _ifNameList.last() + "\"]"; + chooseInterfaceDialog(jsonArr); + } else { + foreach(QString i, _ifNameList) + { + if (_networkDiscovery->checkConnectivity(i)) { + continueBootWithoutCheck(i); + break; + } + } + } + } else { + qxtLog->debug() << _tag << " No usable interfaces found!: " + << _networkDiscovery->GetErrorStr(); + qxtLog->debug() << _tag << " list is empty"; + abortBoot("No usable interfaces found!" + + _networkDiscovery->GetErrorStr()); + } +} + + + +/** + * @brief restart the system + * + * this method will restart the system. + * triggered through a button click in the gui. + */ +void ndgui::restartSystem() { + QFile file("/proc/sysrq-trigger"); + if (file.open(QIODevice::WriteOnly)) { + file.write("b"); + file.close(); + } else { + qxtLog->debug() << _tag << "Could not open /proc/sysrq-trigger"; + } +} + + + +/** + * @brief shut down the system + * + * this method will restart the system. + * triggered through a button click in the gui. + */ +void ndgui::shutDownSystem() { + QFile file("/proc/sysrq-trigger"); + if (file.open(QIODevice::WriteOnly)) { + file.write("o"); + file.close(); + } else { + qxtLog->debug() << _tag << "Could not open /proc/sysrq-trigger"; + } +} + + + +/** + * @brief continue the boot sequence + * + * represents the end of the NetworkDiscovery life time. + * will start the fbgui screen. All networkDiscovery signals + * will be ignored after this point. + */ +//void ndgui::continueBoot(QString ifName, int userChoice) { +void ndgui::continueBoot(QString ifName) { + if (_networkDiscovery->checkConnectivity(ifName)) { + qxtLog->debug() << _tag << " continue with interface: " << ifName; + emit initFbgui(); + this->close(); + } else { + abortBoot( + "Interface was suddenly made unusable. Please check the log and try again."); + } + +} + + + +/** + * @brief continue the boot sequence without further checking if the connection is still possible. + */ +void ndgui::continueBootWithoutCheck(QString ifName) { + qxtLog->debug() << _tag << " continue with interface: " << ifName; + emit initFbgui(); + this->close(); +} + + + +/** + * @brief read the log file. Log File will be presented inside of a dialog. + */ +QString ndgui::readLogFile() { + qxtLog->debug() << _tag << "show log"; + return _networkDiscovery->readLogFile(); +} + + + +/** + * @brief starts the whole application again. + */ +void ndgui::tryAgain() { + qxtLog->debug()<< _tag << " try again "; + _networkDiscovery->prepareTryAgain(); + if(debugMode > -1) { + delete _splitter; + delete _debugConsole; + delete _toggleDebugConsole; + } + delete _allowUserChoice; + delete _tryAgain; + delete _webView; + delete _networkDiscovery; + + init(); + +} + + + +/*test html gui version*/ + +/** + * @brief fills the drop down box of the manual interface configuration + * dialog. + */ +QVariantList ndgui::getManualConfInterfaces() { + qxtLog->debug() << _tag << "call getManualConfInterfaces"; + QVariantList jsonArr; + foreach (QString s, _manConfList) { + QVariant e(s); + jsonArr << e; + } + qxtLog->debug() << _tag << "value of jsonArr:" << jsonArr; + return jsonArr; +} + + +/** + * @brief return a json formated interface configuration + * + * @param ifName + * the name of the interface + */ +QVariantMap ndgui::getInterfaceConf(QString ifName) { + + return _networkDiscovery->getInterfaceConfig(ifName); +} + + + +/** + * @brief takes the entered manual configuration dates and delivers it + * to the networkDiscovery for further actions. + * + * @param jsonArr + * a jsonArr which contains the manual entered interface configuration + */ +int ndgui::ip4_setManualConfiguration(QVariantMap jsonArr) { + return _networkDiscovery->ip4_setManualConfiguration(jsonArr); + +} + + + +/* slots */ +/************************************************/ +////////////////////////////////////////////////// +/************************************************/ + +/** + * @brief stellt ein ndgui/fbgui Objekt zur verwendung durch die html bereit. + */ +void ndgui::attachToDOM(){ + _webView->page()->mainFrame()->addToJavaScriptWindowObject(QString("fbgui"), this); + loadJQuery(); +} + + + +/** + * @brief load jQuery and js scripts into the page so that all javascript functions will work. + */ +void ndgui::loadJQuery() { + QString js; + QString pathToJsDir(":/html"); + pathToJsDir.append("/js"); + + QDir qrcJSDir(pathToJsDir); + QFileInfoList fiList = qrcJSDir.entryInfoList(); + QFileInfo fi; + foreach(fi, fiList) + { + if (fi.suffix() == "js") { + //qxtLog->debug()<< fi.fileName(); + //qxtLog->debug() << fi.fileName(); + //if (fi.fileName() != "test.js" && fi.fileName() != "nd-functions.js") { + QFile file; + file.setFileName(pathToJsDir + "/" + fi.fileName()); + file.open(QIODevice::ReadOnly); + js = file.readAll(); + file.close(); + + _webView->page()->mainFrame()->evaluateJavaScript(js); + //qxtLog->debug() << "evaluated " + fi.fileName(); + //} + } + } +} + + + + +/** + * @brief show abortBoot dialog + * + * @param msg + * the message, displayed in the dialog. + */ +void ndgui::abortBoot(const QString msg) { + QString code = QString("abortBootDialog('\%1')").arg(msg); + _webView->page()->mainFrame()->evaluateJavaScript(code); +} + + + +/** + * @brief opens ths chooseInterfaceDialog + * + * @param msg + * the interfaces as json formated string. will be displayed in a select box. + */ +void ndgui::chooseInterfaceDialog(const QString msg) { + QString code = QString("chooseInterfaceDialog(\%1)").arg(msg); + _webView->page()->mainFrame()->evaluateJavaScript(code); +} + + + +/** + * @brief updates the over all status + * + * @param status + * the new status message + */ +void ndgui::updateStatus(const QString &status) { + if (status == "") + return; + QString code = QString("updateStatus('\%1')").arg(status); + _webView->page()->mainFrame()->evaluateJavaScript(code); +} + + + +/** + * @brief updates the progress bar for each interface. + * + * @param ifname + * the name ot the interface to update + * + * @param percent + * the progress in percent + */ +void ndgui::updateIfProgressBar(const QString &ifName, const int& percent) { + if (percent == 0) + return; + QString code = QString("updateIfProgressBar('\%1',\%2)").arg(ifName).arg(percent); + _webView->page()->mainFrame()->evaluateJavaScript(code); +} + + + +/** + * @brief update the status for each interface + * + * @param ifName + * the name ot the interface to update + * + * @param status + * the new status of the interface. + */ +void ndgui::updateIfStatus(const QString &ifName, const QString &status) { + if (ifName == "") + return; + QString code = QString("updateIfStatus('\%1','\%2')").arg(ifName).arg(status); + _webView->page()->mainFrame()->evaluateJavaScript(code); +} + + + +/** + * @brief adds an interface to the DOM tree. Creates its progress bar and it's status label. + * + * @param ifName + * name of the new interface. + */ +void ndgui::addInterface(const QString &ifName) { + if (ifName == "") + return; + _manConfList.append(ifName); + QString code = QString("addInterface('\%1')").arg(ifName); + _webView->page()->mainFrame()->evaluateJavaScript(code); +} + + + +/** + * @brief just for debugging. + */ +void ndgui::notifyCall(QString msg){ + qxtLog->debug() << _tag << "------ called:" << msg; +} diff --git a/src/fbgui/ndgui.h b/src/fbgui/ndgui.h new file mode 100644 index 0000000..41a7bbf --- /dev/null +++ b/src/fbgui/ndgui.h @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + */ + + + +#ifndef NDGUI_H +#define NDGUI_H + +#include +#include +#include + +#include "fbgui.h" +#include "loggerengine.h" +#include "networkdiscovery.h" + + +extern QString gServerIp; +extern bool gAutoUp; +extern QString gSocketServerPath; +extern QString gPathToDhcpExe; + +class ndgui: public QMainWindow { +Q_OBJECT + +public: + ndgui(QMainWindow *parent = 0); + ~ndgui(); + Q_INVOKABLE QVariantList getManualConfInterfaces(); + Q_INVOKABLE int ip4_setManualConfiguration(QVariantMap result); + Q_INVOKABLE QString readLogFile(); + Q_INVOKABLE QVariantMap getInterfaceConf(QString ifName); + +public slots: + void handleConnectionEstablished(QString ifName); + void abortBoot(QString msg); + void chooseInterfaceDialog(QString msg); + void handleAllProcessesFinished(); + + void restartSystem(); + void shutDownSystem(); + void continueBoot(QString ifName); + void continueBootWithoutCheck(QString ifName); + void tryAgain(); + + + void startSingleShot(); + void startNetworkDiscovery(); + + /*test for html gui version*/ + void attachToDOM(); + void loadJQuery(); + void addInterface(const QString &ifName); + void updateIfStatus(const QString &ifName, const QString &status); + void updateStatus(const QString &status); + void updateIfProgressBar(const QString &ifName, const int& percent); + void notifyCall(QString msg); + + signals: + void initFbgui(); + +private slots: + void setUserChoiceTrue(); + +private: + + QString _tag; + + void createAction(); + + bool _userChoice; + + bool _started; + + QWebView* _webView; + + QAction* _allowUserChoice; + + QAction* _tryAgain; + + NetworkDiscovery* _networkDiscovery; + + QList _ifNameList; // maps interfaceName to its gateway + + QList _manConfList; + + QString _manualConfInterfaces; + + // QSplitter to split the main window in two resizable frames. + QSplitter* _splitter; + // QTextEdit implementing a minimalistic debug console. + QTextEdit* _debugConsole; + + // triggers toggleDebugConsole() + QAction* _toggleDebugConsole; + + void init(); + void setupLayout(); + void createDebugConsole(); + void toggleDebugConsole(); + + +}; + +#endif // NDGUI_H diff --git a/src/fbgui/networkdiscovery.cpp b/src/fbgui/networkdiscovery.cpp new file mode 100644 index 0000000..132429c --- /dev/null +++ b/src/fbgui/networkdiscovery.cpp @@ -0,0 +1,990 @@ +/** + * @class NetworkDiscovery + * + * @brief the logic behind the NetworkDiscovery. + * + * This class holds all the logic of the NetworkDiscovery. It's main task is to search for usable + * interfaces, check if they are wired (in Running state) and start a cdhcpcd process for each interface. + * It also sends signals to the ndgui class for presenting notifications to the user. + * + */ + + + +#include +#include + +#include "networkdiscovery.h" + + + + +/** + * constructor + */ +NetworkDiscovery::NetworkDiscovery(QObject *parent) { + _tag = "[nd:NetworkDiscovery]"; + _server = new QLocalServer(this); +} + + + +/** + * destructor + */ +NetworkDiscovery::~NetworkDiscovery() { + delete _networkManager; + delete _server; + foreach(QProcess* p, _clientProcessToIfNameMap.keys()) { + delete p; + } + foreach(interfaceconfiguration* i, _ifcMap.values()) { + delete i; + } +} + + + +/** + * initialize all important class members and start the main work. + * + * @param serverIp + * the ip of the server with which we are testing the connectivity. + * + * @param userChoice + * true if the user wishes to have a user choice. true: the chooseInterfaceDialog will be showed. + * + * @param autoUp + * true if we want to "auto Up" all down interfaces. + * + * @param pathToLogFile + * the path to the log file. + * + * @param serverPath + * the path to the server socket (default value: DEFAULT_QTSOCKETADDRESS "/var/tmp/qt_c_socket_default") + * + * @param pathToExe + * the path to the customdhcpcd exe. (default value: #define DEFAULT_QTSOCKETADDRESS "/var/tmp/qt_c_socket_default") + * + * @param args + * additional arguments for the customdhcpcd client. (default value: NULL) + */ +void NetworkDiscovery::initAndRun(QString serverIp, bool userChoice, bool autoUp, QString pathToLogFile, QString serverPath, QString pathToExe, + QStringList* args) { + + _serverIp = serverIp; + _userChoice = userChoice; + _autoUp = autoUp; + _pathToLogFile = pathToLogFile; + _serverPath = serverPath; + + _pathToDhcpcdExe = pathToExe; + _blocked = false; + _numberOfProcesses = 0; + _ifUpCountdown = 10; + + _errorStr = ""; + _networkManager = new NetworkManager(); + _clientProcessToIfNameMap.clear(); + _clients.clear(); + _dhcpcdArguments.clear(); + _ifDownList.clear(); + _ifNameToClient.clear(); + _ifUpList.clear(); + _ifcMap.clear(); + _server = new QLocalServer(); + + if (serverPath != DEFAULT_QTSOCKETADDRESS) { + _dhcpcdArguments.append("-q"); + _dhcpcdArguments.append(serverPath); + } + /* delete the file at serverPath. this is necessary since in case the application crashes, the file still + * exists which leads to an error. + */ + + if(QFile::exists(serverPath)) { + QFile::remove(serverPath); + } + + emit updateStatus("try to create server socket"); + if (!_server->listen(serverPath)) { + // emit signal to the gui that a critial error occoured + qxtLog->debug() << _tag << " Unable to start server: " + << _server->errorString(); + emit + abortBoot("Unable to start server: " + _server->errorString()); + return; + } + + killDHCPCD(); + + // check if the path to the customdhcpcd file is correct + emit updateStatus("check if cdhcpcd is available"); + QFileInfo fInfo(_pathToDhcpcdExe); + if (!fInfo.exists()) { + qxtLog->debug() << _tag + << " could not find customdhcpcd exe. Please check the path to this file."; + emit abortBoot( + "could not find customdhcpcd exe. Please check the path to this file."); + return; + } + + connect(_server, SIGNAL(newConnection()), this, SLOT(handleNewConnection())); + connect(this, SIGNAL(readyForRun()), this, SLOT(slotReadyForRun())); + + if (args != NULL && !args->isEmpty()) { + qxtLog->debug() << _tag << "added additional args"; + _dhcpcdArguments.append(*args); + } + emit updateStatus("start mainwork"); + mainWork(); +} + + + +/** + * @brief the main work. Here we start with searching for usable interfaces and check the IsRunning state. + * + * the main work. Here we start with searching for usable interfaces and check the IsRunning state. + * check every second the IsRunning state. Do this as long the counter (@see _ifUpCountdown) is greater than 0. + * Default: _ifUpCountdown = 10. + */ +void NetworkDiscovery::mainWork() +{ + if (_autoUp) { + emit updateStatus("search for usable interfaces (with auto Up)"); + getListOfNetworkInterfacesWithAutoUp(); + } else { + emit updateStatus("search for usable interfaces"); + getListOfNetworkInterfaces(); + } + emit updateStatus("check if interfaces are in running state"); + _timer = new QTimer(this); + connect(_timer, SIGNAL(timeout()), this, SLOT(checkForIsRunning())); + _timer->start(1000); +} + + + +/** + * searches for usable interfaces and puts them into a list. + * if the interface is down, put it in the _ifDownList, try to bring it up. + * else put it in the _ifUpList. + * usable interfaces are: can Broadcast, no loopback, no point to point, name is not in the BlackList, + */ +void NetworkDiscovery::getListOfNetworkInterfacesWithAutoUp() { + QList nIList = QNetworkInterface::allInterfaces(); + _ifUpList.clear(); + _ifDownList.clear(); + if (nIList.size() > 0) { + foreach(QNetworkInterface nI, nIList) + { + qxtLog->debug() << _tag << "found Interface:" << nI.humanReadableName(); + if ((nI.flags() & QNetworkInterface::CanBroadcast)) { + qxtLog->debug() << _tag << " flags: can broadcast "; + } + if ((nI.flags() & QNetworkInterface::IsLoopBack)) { + qxtLog->debug() << _tag << " flags: is LoopBack "; + } + if ((nI.flags() & QNetworkInterface::IsPointToPoint)) { + qxtLog->debug() << _tag << " flags: is Point to Point "; + } + if ((nI.flags() & QNetworkInterface::IsRunning)) { + qxtLog->debug() << _tag << " flags: is Running "; + } + if ((nI.flags() & QNetworkInterface::IsUp)) { + qxtLog->debug() << _tag << " flags: is Up "; + } + + if (((!(nI.flags() & QNetworkInterface::CanBroadcast) + || nI.flags() & QNetworkInterface::IsLoopBack) + || nI.flags() & QNetworkInterface::IsPointToPoint) + || checkBlackList(nI.humanReadableName())) { + continue; + } + if ((nI.flags() & QNetworkInterface::IsRunning)) { + _ifUpList.append(nI.humanReadableName()); + } + else if (!(nI.flags() & QNetworkInterface::IsUp)) { + _networkManager->bringInterfaceUP(nI.humanReadableName()); + qxtLog->debug() << _tag << " interface is down, try to bring up: " << nI.humanReadableName() ; + _ifDownList.append(nI.humanReadableName()); + } + else if (!(nI.flags() & QNetworkInterface::IsRunning)) { + _ifDownList.append(nI.humanReadableName()); + } + } + } else { + qxtLog->debug() << _tag << " no interfaces found! "; + } +} + + + +/** + * searches for usable interfaces which are up and running and put them into a list. + * usable interfaces are: can Broadcast, no loopback, no point to point, name is not in the BlackList, + */ +void NetworkDiscovery::getListOfNetworkInterfaces() { + QList nIList = QNetworkInterface::allInterfaces(); + _ifUpList.clear(); + _ifDownList.clear(); + if (nIList.size() > 0) { + foreach(QNetworkInterface nI, nIList) + { + qxtLog->debug() << _tag << "found Interface:" + << nI.humanReadableName(); + if ((nI.flags() & QNetworkInterface::CanBroadcast)) { + qxtLog->debug() << _tag << " flags: can broadcast "; + } + if ((nI.flags() & QNetworkInterface::IsLoopBack)) { + qxtLog->debug() << _tag << " flags: is LoopBack "; + } + if ((nI.flags() & QNetworkInterface::IsPointToPoint)) { + qxtLog->debug() << _tag << " flags: is Point to Point "; + } + if ((nI.flags() & QNetworkInterface::IsRunning)) { + qxtLog->debug() << _tag << " flags: is Running "; + } + if ((nI.flags() & QNetworkInterface::IsUp)) { + qxtLog->debug() << _tag << " flags: is Up "; + } + if (((!(nI.flags() & QNetworkInterface::CanBroadcast) + || nI.flags() & QNetworkInterface::IsLoopBack) + || nI.flags() & QNetworkInterface::IsPointToPoint) + || !(nI.flags() & QNetworkInterface::IsUp) + || checkBlackList(nI.humanReadableName())) { + continue; + } + if (!(nI.flags() & QNetworkInterface::IsRunning)) { + _ifDownList.append(nI.humanReadableName()); + } else { + _ifUpList.append(nI.humanReadableName()); + } + } + } else { + qxtLog->debug() << _tag << " no interfaces found! "; + } +} + + + +/** + * only called if autoUp == true. + * check the IsRunning flag of each interface in the _ifDownList. + * connected to the timeout signal of the timer. + */ +void NetworkDiscovery::checkForIsRunning() { + bool isRunning = false; + foreach(QString i, _ifDownList) { + QNetworkInterface networkInterface = QNetworkInterface::interfaceFromName(i); + isRunning = (networkInterface.flags() & QNetworkInterface::IsRunning); + if (isRunning) { + _ifUpList.append(i); + _ifDownList.removeAt(_ifDownList.indexOf(i)); + } + } + _ifUpCountdown--; + if ((_ifUpCountdown <= 0 ) || _ifDownList.isEmpty()) { + // shut down timer + _timer->stop(); + delete _timer; + emit readyForRun(); + } +} + + + +/** + * emits the addInterface signal for each interface name in _ifUpList + * and calls the runDHCPCD method. + * if the _ifUpList is empty, this method emits an abortBoot signal. + * connected to the readyForRun signal. + */ +void NetworkDiscovery::slotReadyForRun() { + if (_ifUpList.size() > 0) { + foreach(QString i, _ifUpList) { + qxtLog->debug() << _tag << " emit addInterface : " << i; + emit addInterface(i); + } + _numberOfProcesses = _ifUpList.size(); + emit updateStatus("start dhcp client for each interface"); + runDHCPCD( _ifUpList); + } else { + qxtLog->debug() << _tag << " list is empty. Have not found usable interface. "; + emit + foreach(QString i, _ifDownList) { + qxtLog->debug() << _tag << " " << i << " is not in running state. (check cable)"; + } + abortBoot("All interfaces are not usable. (e.g. please check if all network cables are plugged in. Read the log for more informations.)"); + return; + } +} + + + +/** + * call for every interface in the list the runDHCPCD method. + * + * @param interfaces + * list of interface names. + */ +void NetworkDiscovery::runDHCPCD(QList &interfaces) { + foreach(QString nI, interfaces) + { + runDHCPCD(nI); + } +} + + + +/** + * start a cdhcpcd process with the interface name as last argument. + * + * @param interface + * name of an interface. + */ +void NetworkDiscovery::runDHCPCD(QString interface) { + emit updateIfStatus(interface, "start DHCP"); + _dhcpcdArguments.append(interface); + QProcess * p = new QProcess(this); + + qxtLog->debug() << _tag << " start cdhcpcd with arguments: " << _dhcpcdArguments; + + _clientProcessToIfNameMap.insert(p, interface); + p->start(_pathToDhcpcdExe, _dhcpcdArguments); + connect(p, SIGNAL(started()), this, SLOT(handleProcessStarted())); + connect(p, SIGNAL(finished(int, QProcess::ExitStatus)), this, + SLOT(handleProcessFinished(int, QProcess::ExitStatus))); + _dhcpcdArguments.removeLast(); +} + + + +/** + * This Method is called when a process is started. + * + * This Method is called when a process is started. + * It prints the message: "process started for interface: ". + */ +void NetworkDiscovery::handleProcessStarted() { + QProcess* p = qobject_cast (QObject::sender()); + QString ifName = _clientProcessToIfNameMap.value(p, "ifName"); + qxtLog->debug() << _tag << " process started for interface: " << ifName; +} + + + +/** + * This Method is called when a process is finished. + * + * This Method is called when a process is finished. This slot is connected + * with the signal finished() of the QProcess class. + * If the process finishes, it will be checked if the process exited normal + * or if an unexpected error occurred. For this, we determine the sender (which is a + * QProcess), get the corresponding interface (which is stored in a map), and check + * the exitCode. Further actions are taken according to the exitCode check. + * Normal exit: + * emit changeProgressBar() to 100% + * emit updateIfStatus() to check connection + * checkConnectivity() @see NetworkDiscovery::checkConnectivity() + * Unexpected exit: + * emit updateIfStatus() to process exited unexpected + * + * @param exitCode + * + * @param exitStatus + * + * @return bool + * returns true: if the interface name i starts with a letter in the blacklist. + * + * returns false: else + * + * @see NetworkDiscovery::getListOfNetworkInterfaces() + */ +void NetworkDiscovery::handleProcessFinished(int exitCode, + QProcess::ExitStatus exitStatus) { + + QProcess* p = qobject_cast (QObject::sender()); + QString ifName = _clientProcessToIfNameMap.value(p, "ifName"); + _numberOfProcesses = _numberOfProcesses - 1; + if (!_blocked) { //_blocked becomes true, if _userChoice is false and we already found a usable interface + if (ifName.compare("ifName") == 0) { + qxtLog->debug() << _tag << " haven't found process!"; + } else { + qxtLog->debug() << _tag << " process for interface " << ifName + << " finished " << " exit code: " << exitCode + << " exit status " << exitStatus; + if (exitCode > 0) { + qxtLog->debug() << _tag << " process exited unexpected: " + << p->errorString(); + emit updateIfStatus(ifName, "process exited unexpected" + + p->errorString()); + } else { + qxtLog->debug() << _tag << " process normal exit "; + emit + changeProgressBarValue(ifName, 100); + emit + updateIfStatus(ifName, "check connectivity"); + if (checkConnectivity(ifName)) { + emit connectionEstablished(ifName); + if (!_userChoice) { + // blockiere jeden weiteren check + _blocked = true; + emit allProcessesFinished(); + } + } + } + } + if (!_blocked) { //_blocked becomes true, if _userChoice is false and we found a usable interface + QLocalSocket *client = _ifNameToClient.value(ifName, 0); + if (client != 0) { + handleNewInput(client); + } + //_numberOfProcesses = _numberOfProcesses - 1; && _userChoice + if (_numberOfProcesses <= 0) { + emit allProcessesFinished(); + } + } + } else { + qxtLog->debug() << _tag << " already blocked"; + emit updateIfStatus(ifName, "finished DHCP"); + } +} + + + +/** + * checks the connectivity. tries to open a TCP connection to the + * server (see _serverIp). For this it adjusts the routing table. + * (sets the gateway of the interface as default gateway) + * Gateway is written into the dhcpcd config file of this interface. + * (see DEFAULT_INTERFACE_CONF_LOCATION "/var/tmp/conf_") + * + * @param ifName + * name of a interface. + * + * @return + * true: connection is possible + * false: connection not possible + */ +bool NetworkDiscovery::checkConnectivity(QString ifName) { + int mss = 0; + + // get gateway address + QString pathToGatewayFile(DEFAULT_INTERFACE_CONF_LOCATION); + pathToGatewayFile += ifName; + interfaceconfiguration* ifConf; + if (!_ifcMap.contains(ifName)) { + ifConf = new interfaceconfiguration(); + _ifcMap.insert(ifName, ifConf); + } + else { + ifConf = _ifcMap.value(ifName); + } + ifConf->readConfigOutOfFile(pathToGatewayFile); + + // replace default route + qxtLog->debug() << _tag << "replace default route"; + _networkManager->replaceDefaultRoute(ifName, + ifConf->getGateway(), mss, AF_INET); + + if (checkConnectivityViaTcp(_serverIp)) { + qxtLog->debug() << _tag << " passed connectivity check! for interface " << ifName; + emit + updateIfStatus(ifName, "connection possible"); + return true; + } else { + qxtLog->debug() << _tag << " failed connectivity check! for interface " << ifName; + emit + updateIfStatus(ifName, "connection not possible"); + return false; + } +} + + + +/**/ +bool NetworkDiscovery::checkConnectivityViaTcp() { + return checkConnectivityViaTcp(_serverIp); +} + + + +/** + * try to open a tcp connection to the server + * + * @param server + * a ip address. + * + * @return + * true: connection is possible + * false: connection not possible + */ +bool NetworkDiscovery::checkConnectivityViaTcp(QString server) { + // check connectivity via tcp connection + qxtLog->debug() << _tag << " check connectivity to server: " << server; + // do host lookup + //QHostInfo hostInfo = QHostInfo::fromName(server); + QTcpSocket *tcpSocket = new QTcpSocket(this); + //qxtLog->debug() << _tag << " hostInfo first address: " << hostInfo.addresses().first().toString(); //hostInfo.addresses().first() + tcpSocket->connectToHost(server, 80); + if (!tcpSocket->waitForConnected(500)) { + qxtLog->debug() << _tag << tcpSocket->errorString(); + _errorStr += tcpSocket->errorString(); + return false; + } else { + return true; + } + delete tcpSocket; +} + + + +/** + * same function as handleNewInput() but with a client as parameter. + * + * @param cleint + * a client + */ +void NetworkDiscovery::handleNewInput(QLocalSocket * client) { + qxtLog->debug() << _tag << "last read before exit"; + while (client->canReadLine()) { + QString data(client->readLine()); + + data = data.trimmed(); + qxtLog->debug() << _tag << data; + QStringList lines = data.split("\n"); + + for (int i = 0; i < lines.length(); i++) { + handleNewInputLine(client, lines.at(i)); + } + } +} + + + +/** + * This method is connected to the readyRead Signal of the QLocalSocket + * client. + * send an ACK to the client with every received message. + */ +void NetworkDiscovery::handleNewInput() { + QLocalSocket* socket = qobject_cast (QObject::sender()); + + QLocalSocket * client = _clients.value(socket); + QString data(client->read(DHCP_MESSAGE_SIZE)); + data = data.trimmed(); + QStringList lines = data.split("\n"); + for (int i = 0; i < lines.length(); i++) { + handleNewInputLine(client, lines.at(i)); + } +} + + + +/** + * This Method processes the send messages. + * + * This Method processes the send messages. It splits the line + * into several components. Those components are: + * interface: interface name ==> indicates the process who send the message + * s_state: is the number representation of syslog.h LOG levels + * s_subState: is the number representation of the dhcp.c DHCP states (1 - 8) plus + * the status. h states (9 - ..) + * msg: is a message which can contain additional informations + * + * According to the s_state and s_subState we emit the changeProgressBarValue() signal + * with different values. + * + * @param client + * the client who send the message + * + * @param data + * the message. (format ;;; ) + */ +void NetworkDiscovery::handleNewInputLine(QLocalSocket * client, QString data) { + + QString logMsg(data); + QString interface = logMsg.section(";", 0, 0); + QString s_state = logMsg.section(";", 1, 1); + QString s_subState = logMsg.section(";", 2, 2); + QString msg = logMsg.section(";", 3, 3); + int st = s_state.trimmed().toInt(); + int sst = s_subState.trimmed().toInt(); + //qxtLog->debug() << _tag << logMsg; + + if (_ifNameToClient.size() < _numberOfProcesses && !_ifNameToClient.contains( + interface)) { + _ifNameToClient.insert(interface, client); + } + + switch (st) { + case LOG_INFO: + switch (sst) { + case DHCP_DISCOVER: + emit changeProgressBarValue(interface, 10); + qxtLog->debug() << _tag << " " << interface << " send discover"; + break; + case DHCP_OFFER: + emit changeProgressBarValue(interface, 20); + qxtLog->debug() << _tag << " " << interface << " got offer"; + break; + case DHCP_REQUEST: + emit changeProgressBarValue(interface, 30); + qxtLog->debug() << _tag << " " << interface << " send request"; + break; + case DHCP_ACK: + emit changeProgressBarValue(interface, 40); + qxtLog->debug() << _tag << " " << interface << " ack"; + break; + case DHCP_NAK: + emit changeProgressBarValue(interface, 40); + qxtLog->debug() << _tag << " " << interface << " nak"; + break; + case DHCPCD_ARP_TEST: + emit changeProgressBarValue(interface, 50); + qxtLog->debug() << _tag << " " << interface << " do arp test"; + break; + case DHCP_DECLINE: + emit changeProgressBarValue(interface, 60); + break; + case DHCP_RELEASE: + qxtLog->debug() << _tag << " " << interface << " release"; + break; + case DHCP_INFORM: + break; + case DHCPCD_CONFIGURE: + emit changeProgressBarValue(interface, 70); + qxtLog->debug() << _tag << " " << interface << " do configure interface"; + break; + case DHCPCD_WRITE: + emit changeProgressBarValue(interface, 80); + qxtLog->debug() << _tag << " " << interface << " write conf file"; + break; + case DHCPCD_EXIT: + emit changeProgressBarValue(interface, 100); + qxtLog->debug() << _tag << " " << interface << " exiting"; + break; + case DHCPCD_LOG: + qxtLog->debug() << _tag << " received dhcpcd log: " << msg; + default: + qxtLog->debug() << _tag << " received unknown substatus: " << msg; + break; + } + break; + case LOG_ERR: + qxtLog->debug() << _tag << " received error: " << msg; + break; + default: + qxtLog->debug() << _tag << " " << logMsg; + break; + } +} + + + +/** + * replace the default route. sets af automatically to AF_INET + * + * @param ifName + * interface name + * + * @param gateway + * gateway address + * + * @param mss + * mss value (i think this is the metric. in most cases this value is 0) + */ +int NetworkDiscovery::ip4_replaceDefaultRoute(QString ifName, QString gateway, int mss) { + return _networkManager->replaceDefaultRoute(ifName, gateway, mss, AF_INET); +} + + + +/** + * replace the dhcp configuration with the manual config, entered by the user. + * if we can not establish a connection with the entered values, reset to the old + * dhcp values. + * + * @param result + * a json object formated string. + * + * @return + * 0 if everything ok + */ +int NetworkDiscovery::ip4_setManualConfiguration(QVariantMap result) { + QList dns; + dns.append(result["dns"].toString()); + _networkManager->ip4_setManualConfiguration(result["ifname"].toString(), + result["ipaddr"].toString(), result["netmask"].toString(), + result["broadcast"].toString(), result["gateway"].toString(), 0, + AF_INET, "/etc/", dns); + + qxtLog->debug() << _tag << " set man conf. and check connectivity"; + + if (!checkConnectivityViaTcp(_serverIp)) { + qxtLog->debug() << _tag << " no connectivity. reset conf."; + interfaceconfiguration * ifc = _ifcMap.value( + result["ifname"].toString(), NULL); + if (ifc != NULL) { + dns.clear(); + dns = ifc->getDnsservers().trimmed().split(" "); + _networkManager->ip4_setManualConfiguration( + result["ifname"].toString(), ifc->getIpAddress(), + ifc->getNetmask(), ifc->getBroadcast(), ifc->getGateway(), + 0, AF_INET, "/etc/", dns); + } + + return 0; + } + qxtLog->debug() << _tag << " emit signal continueBootWithoutCheck(" << result["ifname"].toString() << ")"; + emit + continueBootWithoutCheck(result["ifname"].toString()); + return 0; +} + + + +/** + * returns the gateway address, written into the dhcp config file. + * + * @param ifName + * name of the interface. + * + * @return + * gateway address as string. or empty string if no interface config was found. + */ +QString NetworkDiscovery::getGatewayForInterface(QString ifName) { + interfaceconfiguration * ifConf = _ifcMap.value(ifName, NULL); + if (ifConf != NULL) + { + return ifConf->getGateway(); + } + else { + qxtLog->debug() << _tag << " could not find interface configuration"; + return ""; + } + +} + + + +/** + * reads the log file. + * + * @return the log file as one string. + */ +QString NetworkDiscovery::readLogFile() { + // path to log file is in _pathToLogFile. initialized in initAndRun(). + QString retval("the log file\n"); + QFile logFile(_pathToLogFile); + if (logFile.exists()) { + if (logFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + while (!logFile.atEnd()) { + retval.append(logFile.readLine()); + } + } + else { + qxtLog->debug() << _tag << " could not open log file"; + retval = "could not open log file"; + } + } + else { + qxtLog->debug() << _tag << " log file does not exist at: " << _pathToLogFile; + retval = " log file does not exist at: " + _pathToLogFile; + } + return retval; + +} + + +/**/ +void NetworkDiscovery::killDHCPCD() { + qxtLog->debug() << " kill cdhcpcd processes"; + QProcess * p = new QProcess(this); + p->start("killall cdhcpcd"); + p->waitForFinished(); + if (p->exitCode() > 0) + qxtLog->debug() << _tag << " [tryAgain] " << p->errorString(); + + delete p; +} + + + +/**/ +void NetworkDiscovery::prepareTryAgain() { + // kill all cdhcpcd processes + killDHCPCD(); + + /* + foreach(Q_PID pid , _pidsList) { + if (kill(pid,SIGKILL) <= -1) + qDebug() << _tag << " error: trying to kill process: " << pid << " error: " << strerror(errno); + } + */ + // reset everything + delete _networkManager; + delete _server; + foreach(QProcess* p, _clientProcessToIfNameMap.keys()) + { + delete p; + } + foreach(interfaceconfiguration* i, _ifcMap.values()) + { + delete i; + } +} + + + +/* + *TODO: to be bug fixed + *TODO: do it with kill and not QProcess("killall cdhcpcd") + */ +void NetworkDiscovery::tryAgain() { + prepareTryAgain(); + initAndRun(_serverIp, _userChoice, _autoUp, _pathToLogFile, _serverPath, DEFAULT_PATHTODHCPCDEXE); +} + + + +/**/ +QVariantMap NetworkDiscovery::getInterfaceConfig(QString ifName) { + QVariantMap jsonObj; + QList dns; + interfaceconfiguration * ifc = _ifcMap.value(ifName, NULL); + if (ifc != NULL) { + jsonObj.insert("ipaddr",ifc->getIpAddress()); + jsonObj.insert("netmask",ifc->getNetmask()); + jsonObj.insert("broadcast",ifc->getBroadcast()); + jsonObj.insert("gateway",ifc->getGateway()); + + dns.clear(); + dns = ifc->getDnsservers().trimmed().split(" "); + jsonObj.insert("dns",dns.first()); + } + return jsonObj; +} + + + +/** + * connected to the new client arrived signal. + * connects the client readyRead signal with the handleNewInput slot. + */ +void NetworkDiscovery::handleNewConnection() { + qxtLog->debug() << _tag << " New Connection arrived"; + + /*QLocalSocket **/ + _client = _server->nextPendingConnection(); + _clients.insert(_client, _client); + connect(_client, SIGNAL(disconnected()), this, + SLOT(handleClientDisconnect())); + connect(_client, SIGNAL(readyRead()), this, SLOT(handleNewInput())); +} + + + +/** + * called when a client disconnects. + */ +void NetworkDiscovery::handleClientDisconnect() { + QLocalSocket* socket = qobject_cast (QObject::sender()); + + QLocalSocket * client = _clients.value(socket); + + qxtLog->debug() << _tag << " disconnect client"; + handleNewInput(client); + client->deleteLater(); +} + + + +/** + * This Method implements a blacklist. + * + * This Method implements a blacklist. We check the fist character + * of the interface name. if this letter is in the list, we return true. + * True means, that this interface won't be put into the result list of + * getListOfNetworkInterfaces(). + * + * @param i + * is a interface name. + * + * @return bool + * returns true: if the interface name i starts with a letter in the blacklist. + * + * returns false: else + * + * @see NetworkDiscovery::getListOfNetworkInterfaces() + */ +bool NetworkDiscovery::checkBlackList(QString i) { + if (i.startsWith("v", Qt::CaseInsensitive)) { + return true; + } else if (i.startsWith("d", Qt::CaseInsensitive)) { + return true; + } else { + return false; + } +} + + + +/**/ +QString NetworkDiscovery::GetErrorStr() { + return _errorStr; +} + + + +////////////////////////////////////////////////////////////////////////////////////// + +/** + * not used so far. checks the carrier state using the sysfs library. + * if carrier = 1 ==> the interface is running. + * interfaces have to be up in order to get right results. + * + * @param interface + * name of the interface + */ +bool NetworkDiscovery::checkCarrierState(QString interface) { + + qxtLog->debug() << _tag << "check carrier state for interface " << interface; + QByteArray ba = interface.toAscii(); + const char * iface = ba.data(); + + struct sysfs_class_device *class_device = sysfs_open_class_device("net", + iface); + struct dlist *attrlist = sysfs_get_classdev_attributes(class_device); + if (attrlist != NULL) { + struct sysfs_attribute *attr = NULL; + dlist_for_each_data(attrlist, attr, struct sysfs_attribute) { + if (strcmp("carrier", attr->name) == 0) { + QString value(attr->value); + bool ok = false; + bool * pok = &ok; + int v = value.toInt(pok); + if (*pok) { + if (v == 1) { + qxtLog->debug() + << "carrier is 1. Cable is plugged. return true"; + return true; + } else { + qxtLog->debug() + << "carrier is 0. Cable is unplugged. return false"; + return false; + } + } else { + qxtLog->debug() << _tag << "conversion error"; + } + } + } + } else { + qxtLog->debug() << _tag << "attrlist is Null"; + } + sysfs_close_class_device(class_device); + + return true; +} diff --git a/src/fbgui/networkdiscovery.h b/src/fbgui/networkdiscovery.h new file mode 100644 index 0000000..c422b18 --- /dev/null +++ b/src/fbgui/networkdiscovery.h @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + */ + + + +#ifndef NetworkDiscovery_H +#define NetworkDiscovery_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "loggerengine.h" +#include "interfaceconfiguration.h" +#include "networkmanager.h" + + +#include "dhcp.h" + +#include "../common/fbgui.h" + + + +#define DEFAULT_PATHTODHCPCDEXE "/bin/cdhcpcd" + +class NetworkDiscovery: public QObject { +Q_OBJECT + +public: + NetworkDiscovery(QObject *parent=0); + ~NetworkDiscovery(); + + void initAndRun(QString serverIp, bool userChoice, + bool autoUp, + QString pathToLogFile, + QString serverPath = DEFAULT_QTSOCKETADDRESS, + QString pathToExe = DEFAULT_PATHTODHCPCDEXE, + QStringList* args = NULL); + int ip4_replaceDefaultRoute(QString ifName, QString gateway, int mss); + QString getGatewayForInterface(QString ifName); + + int ip4_setManualConfiguration(QVariantMap result); + QString readLogFile(); + void tryAgain(); + void prepareTryAgain(); + bool checkConnectivity(QString ifName); + bool checkConnectivityViaTcp(); + QVariantMap getInterfaceConfig(QString ifName); + QString GetErrorStr(); + +public slots: + void handleNewConnection(); + void handleNewInput(); + void handleNewInputLine(QLocalSocket * client, QString data); + void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); + void handleProcessStarted(); + void handleClientDisconnect(); + + void slotReadyForRun(); + + void checkForIsRunning(); + + +signals: + void addInterface(const QString &ifName); + void changeProgressBarValue(const QString & ifName, const int $newValue); + void connectionEstablished(QString ifName); + void abortBoot(QString msg); + void updateIfStatus(QString ifName, QString status); + void updateStatus(QString status); + void allProcessesFinished(); + void continueBoot(QString ifName); + void continueBootWithoutCheck(QString ifName); + void setManualConfInterfaces(QString jsonArr); + + void readyForRun(); + +private: + QString _tag; + QLocalServer *_server; + QMap _clients; + QLocalSocket *_client; + QMap _ifNameToClient; + QMap _clientProcessToIfNameMap; + QString _serverPath; + QString _pathToDhcpcdExe; + QStringList _dhcpcdArguments; + int _numberOfProcesses; + NetworkManager* _networkManager; + bool _userChoice; + bool _blocked; + bool _autoUp; + QString _serverIp; + QString _pathToLogFile; + QList _ifUpList; + QList _ifDownList; + int _ifUpCountdown; + QTimer*_timer; + QList _pidsList; + QString _errorStr; + QMap _ifcMap; + void mainWork(); + + void killDHCPCD(); + + void handleNewInput(QLocalSocket * client); + + void runDHCPCD(QList &interfaces); + void runDHCPCD(QString interface); + + bool checkCarrierState(QString interface); + bool checkConnectivityViaTcp(QString server); + + bool checkBlackList(QString i); + + void getListOfNetworkInterfaces(); + void getListOfNetworkInterfacesWithAutoUp(); + + +}; + +#endif // NetworkDiscovery_H diff --git a/src/fbgui/networkmanager.cpp b/src/fbgui/networkmanager.cpp new file mode 100644 index 0000000..2dc774f --- /dev/null +++ b/src/fbgui/networkmanager.cpp @@ -0,0 +1,681 @@ +/** + * @class NetworkManager + * + * @brief Manages the network configurations like setting new default routes. + * + * Manages the network configurations like setting new default routes. + * It provides methods for ipv4 and some method for ipv6. + * + */ + + + +#include "networkmanager.h" + +NetworkManager::NetworkManager() { + // TODO Auto-generated constructor stub + _tag = "[nd:NetworkManager]"; +} + + + +NetworkManager::~NetworkManager() { + // TODO Auto-generated destructor stub +} + + + +/** + * This method adds /replaces the default route. + * This method adds /replaces the default route. + * To keep it modular, it is possible + * to specify an ip address family. + * + * @param ifName + * the interface name + * + * @param gateway + * the gateway address (e.g: 192.168.0.254) + * @param mss + * the mss. + * @param af + * specify the family type of the ip address. + * possible values are: AF_INET for an IPv4 address + * AF_INET6 for an IPv6 address + * + + * @return + * return -1 if an error happened. + * return 0 if everything was ok. + */ +int NetworkManager::replaceDefaultRoute(QString ifname, QString gateway, + int mss, int af) { + struct nl_cache *cache; + struct nl_handle* rtsock; + struct nl_addr * gw; + struct rtnl_route * route; + int retval, iface_idx; + + QByteArray ba_ifn = ifname.toAscii(); + char * ifn = ba_ifn.data(); + + QByteArray ba_gw = gateway.toAscii(); + char * gwaddr = ba_gw.data(); + + qDebug() << _tag << "---doRoute() gwaddr" << gwaddr; + + if (!(gw = nl_addr_parse(gwaddr, af))) { + qDebug() << _tag << "Invalid router address given:" << gwaddr; + return -1; + } + + rtsock = nl_handle_alloc(); + nl_connect(rtsock, NETLINK_ROUTE); + + if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) { + qDebug() << _tag << "error with link cache alloc \n"; + } + + iface_idx = rtnl_link_name2i(cache, ifn); + + route = rtnl_route_alloc(); + rtnl_route_set_scope(route, RT_SCOPE_UNIVERSE); + rtnl_route_set_gateway(route, gw); + rtnl_route_set_oif(route, iface_idx); + + if (mss > 0) { + rtnl_route_set_metric(route, RTAX_ADVMSS, mss); + } + + retval = rtnl_route_add(rtsock, route, NLM_F_REPLACE); + qDebug() << _tag << "return value:" << retval << ":" << strerror(-retval); + + rtnl_route_put(route); + nl_addr_put(gw); + nl_handle_destroy(rtsock); + + return retval; +} + + + +/**/ +int NetworkManager::ip6_addRoute(const char *iface, + const struct in6_addr *ip6_dest, int ip6_prefix, + const struct in6_addr *ip6_gateway, int metric, int mss) { + struct nl_cache *cache; + struct nl_handle *nlh; + struct rtnl_route *route; + struct nl_addr *dest_addr; + struct nl_addr *gw_addr = NULL; + int err, iface_idx; + + nlh = nl_handle_alloc(); + nl_connect(nlh, NETLINK_ROUTE); + + if ((cache = rtnl_link_alloc_cache(nlh)) == NULL) { + //qDebug() << _tag << "error with link cache alloc \n"; + printf("error with link cache alloc \n"); + } + + iface_idx = rtnl_link_name2i(cache, iface); + + route = rtnl_route_alloc(); + + /* Destination */ + dest_addr = nl_addr_build(AF_INET6, (struct in6_addr *) ip6_dest, + sizeof(*ip6_dest)); + nl_addr_set_prefixlen(dest_addr, (int) ip6_prefix); + + rtnl_route_set_dst(route, dest_addr); + nl_addr_put(dest_addr); + + /* Gateway */ + if (ip6_gateway && !IN6_IS_ADDR_UNSPECIFIED (ip6_gateway)) { + gw_addr = nl_addr_build(AF_INET6, (struct in6_addr *) ip6_gateway, + sizeof(*ip6_gateway)); + if (gw_addr) { + rtnl_route_set_gateway(route, gw_addr); + rtnl_route_set_scope(route, RT_SCOPE_UNIVERSE); + } else { + rtnl_route_put(route); + return -1; + } + } + + /* Metric */ + if (metric) + rtnl_route_set_prio(route, metric); + + /* Add the route */ + err = rtnl_route_add(nlh, route, 0); + if (err == -ESRCH && ip6_gateway) { + /* Gateway might be over a bridge; try adding a route to gateway first */ + struct rtnl_route *route2; + + route2 = create_route(iface_idx, mss); + if (route2) { + /* Add route to gateway over bridge */ + rtnl_route_set_dst(route2, gw_addr); + err = rtnl_route_add(nlh, route2, 0); + if (!err) { + /* Try adding the route again */ + err = rtnl_route_add(nlh, route, 0); + if (err) + rtnl_route_del(nlh, route2, 0); + } + rtnl_route_put(route2); + } + } + + if (gw_addr) + nl_addr_put(gw_addr); + + if (err) { + //nm_warning ("Failed to set IPv6 route on '%s': %s", iface, nl_geterror ()); + rtnl_route_put(route); + route = NULL; + } + + return 0; +} + + + +struct rtnl_route * NetworkManager::create_route (int iface_idx, int mss) +{ + struct rtnl_route *route; + + route = rtnl_route_alloc (); + if (route) { + rtnl_route_set_oif (route, iface_idx); + + if (mss && rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0) { + //nm_warning ("Could not set mss"); + } + } else + //nm_warning ("Could not allocate route"); + + return route; +} + + + +/** + * The method brings an interface up. + * + * @param ifname + * the name of the interface + * + * @return + * 0 -> success + * -1 -> error + */ +int NetworkManager::bringInterfaceUP(QString ifname) { + return bringInterfaceUpDown(ifname, true); +} + + + +/** + * The method brings an interface down. + * + * @param ifname + * the name of the interface + * + * @return + * 0 -> success + * -1 -> error + */ +int NetworkManager::bringInterfaceDown(QString ifname) { + return bringInterfaceUpDown(ifname, false); +} + + + +/** + * This method brings an interface up or down. + * + * @param ifname + * is a string which contains the interface name which is going down or up. + * + * @param up + * is a bool. true means. we bring the interface up. + * false meand. we bring the interface down. + * @return + * 0 if everything is ok + * else an error + */ +int NetworkManager::bringInterfaceUpDown(QString ifname, bool up) { + struct nl_cache *cache; + struct nl_handle* rtsock; + struct rtnl_link* request = NULL; + struct rtnl_link* old = NULL; + int retval; + + QByteArray ba_ifn = ifname.toAscii(); + char * ifn = ba_ifn.data(); + + if (!(request = rtnl_link_alloc())) { + qDebug() << _tag << "error. couldn't allocate a rtnl link"; + return -1; + } + + rtsock = nl_handle_alloc(); + nl_connect(rtsock, NETLINK_ROUTE); + + if (up) { + rtnl_link_set_flags(request, IFF_UP); + } else { + rtnl_link_unset_flags(request, IFF_UP); + } + + if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) { + qDebug() << _tag << "error with link cache alloc "; + } + + old = rtnl_link_get_by_name(cache, ifn); + if (old) { + qDebug() << _tag << "change link"; + retval = rtnl_link_change(rtsock, old, request, 0); + } else { + qDebug() << _tag << "change failed"; + retval = -1; + qDebug() << _tag << "return value:" << retval << ":" << strerror(-retval); + } + + rtnl_link_put(old); + rtnl_link_put(request); + nl_handle_destroy(rtsock); + + return retval; +} + + + +/** + * This method is used when the manual configuration is needed. + * + * This method is used when the manual configuration is needed. + * First we bring up the interface. Than we configure the interface with + * our manual entered configuration dates. + * After that we replace the old default route with the new and + * write a resolv.conf. + * + * @param ifname + * name of the interface which we are about to configure. + * + * @param ipAddress + * the new IP-Address. + * + * @param netmask + * the netmask of the IP-Address. + * + * @param broadcast + * the broadcast address. + * @param gateway + * the gateway address. + * @param metric + * do not exactly know why we need this. in most cases this should be 0. + * @param af + * the address type. Either AF_INET for IPv4 or AF_INET6 for IPv6. + * @param pathToResolvConf + * the path to the resolf.conf file. in most cases "/etc/". + * @param nameServer + * the name server addresses. + */ +int NetworkManager::ip4_setManualConfiguration(QString ifname, QString ipAddress, QString netmask, + QString broadcast, QString gateway, int metric, int af, QString pathToResolvConf, QList nameServer) { + + //bring the interface up + bringInterfaceUP(ifname); + //set configuration + ip4_configureInterface(ifname, ipAddress, broadcast, netmask,af); + //set default route + replaceDefaultRoute(ifname, gateway, metric, af); + //write resolv.conf + writeResolvConf(pathToResolvConf, ifname, nameServer); + return 0; +} + + + +int NetworkManager::ip4_configureInterface(QString ifname, QString ipAddress, + QString broadcast, QString netmask, int af) { + + struct nl_cache *cache; + struct nl_handle* rtsock; + struct nl_addr * local; + struct rtnl_addr * addr = NULL; + int retval = 0; + int iface_idx, err, prefixLength; + + QByteArray ba_ifn = ifname.trimmed().toAscii(); + char * ifn = ba_ifn.data(); + + QByteArray ba_ip = ipAddress.trimmed().toAscii(); + char * ipaddr = ba_ip.data(); + + QByteArray ba_bc = broadcast.trimmed().toAscii(); + char * bcaddr = ba_bc.data(); + + rtsock = nl_handle_alloc(); + nl_connect(rtsock, NETLINK_ROUTE); + + if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) { + qDebug() << _tag << "error with link cache alloc"; + return -1; + } + + iface_idx = rtnl_link_name2i(cache, ifn); + + if (!(addr = rtnl_addr_alloc())) { + qDebug() << _tag << "error with addr alloc"; + return -1; + } + + local = nl_addr_parse(ipaddr, af); + err = rtnl_addr_set_local(addr, local); + nl_addr_put(local); + if (err != 0) { + qDebug() << _tag << "error with set local addr"; + } + + prefixLength = ip4_netmaskToPrefix(ipAddress,netmask); + qDebug() << _tag << "prefix length:" << prefixLength; + rtnl_addr_set_prefixlen(addr, prefixLength); + + local = nl_addr_parse(bcaddr, af); + err = rtnl_addr_set_broadcast(addr, local); + nl_addr_put(local); + if (err != 0) { + qDebug() << _tag << "error with set broadcast addr"; + } + + rtnl_addr_set_ifindex(addr, iface_idx); + + + retval = sync_address(ifn, iface_idx, af, addr); + if(retval < 0) { + qDebug() << _tag << "error in sync_address"; + } + rtnl_addr_put(addr); + + return retval; +} + + + +/** + * This Method returns the length of the IP-Address netmask prefix. + * + * @param ipAddr + * the IP-address + * + * @param netmask + * the netmask of the IP-address. + * @return + * the length of the IP-Address netmask prefix + */ +int NetworkManager::ip4_netmaskToPrefix(QString ipAddr, QString netmask) { + int retval = -1; + QNetworkAddressEntry nae; + + if (netmask == "") { + qDebug() << _tag << "error: netmask is empty"; + return retval; + } + nae.setIp(QHostAddress(ipAddr)); + nae.setNetmask(QHostAddress(netmask.trimmed())); + retval = nae.prefixLength(); + + return retval; +} + + + +int NetworkManager::ip6_addAddress(struct ip6_addr* ip6Addr, const char *iface) { + int num_addrs, i, iface_idx; + struct rtnl_addr* addr = NULL; + struct nl_cache *cache; + struct nl_handle* rtsock; + + rtsock = nl_handle_alloc(); + nl_connect(rtsock, NETLINK_ROUTE); + + if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) { + qDebug() << _tag << "error with link cache alloc"; + return -1; + } + + iface_idx = rtnl_link_name2i(cache, iface); + + addr = ip6AddrToRtnlAddr(ip6Addr); + if (!addr) { + //nm_warning("couldn't create rtnl address!\n"); + return -1; + } + rtnl_addr_set_ifindex(addr, iface_idx); + + return sync_address(iface, iface_idx, AF_INET6, addr); +} + + + +/**/ +struct rtnl_addr* NetworkManager::ip6AddrToRtnlAddr(struct ip6_addr* ip6Addr) { + struct rtnl_addr *addr; + bool success = true; + + if (!(addr = rtnl_addr_alloc())) + return NULL; + + success = (nlAddrToRtnlAddr(ip6Addr, addr) >= 0); + + if (!success) { + rtnl_addr_put(addr); + addr = NULL; + } + + return addr; +} + + + +/**/ +struct nl_addr* NetworkManager::ip6AddrToNlAddr(const struct ip6_addr *ip6Addr) { + struct nl_addr * nla = NULL; + + if (!(nla = nl_addr_alloc(sizeof(struct in6_addr)))) + return NULL; + nl_addr_set_family(nla, AF_INET6); + nl_addr_set_binary_addr(nla, (struct in6_addr *) ip6Addr, sizeof(struct in6_addr)); + + return nla; +} + + + +/**/ +int NetworkManager::nlAddrToRtnlAddr( + const struct ip6_addr* ip6Addr, struct rtnl_addr* addr) { + struct nl_addr * local = NULL; + int err = 0; + + local = ip6AddrToNlAddr(ip6Addr); + err = rtnl_addr_set_local(addr, local); + nl_addr_put(local); + + return -err; +} + + + +/** + * delete all addresses of this interface but not the one we just set + * + * @return + * -1 if something went wrong. else 0 + */ +int NetworkManager::sync_address(const char *iface, int ifindex, int family, + struct rtnl_addr *addr) { + + struct nl_handle *nlh; + struct nl_cache *addr_cache; + struct rtnl_addr *filter_addr, *match_addr; + struct nl_object *match; + struct nl_addr *nladdr; + int err; + char buf[INET6_ADDRSTRLEN + 1]; + + nlh = nl_handle_alloc(); + nl_connect(nlh, NETLINK_ROUTE); + + if (!nlh) + return -1; + + addr_cache = rtnl_addr_alloc_cache(nlh); + + if (!addr_cache) + return -1; + + filter_addr = rtnl_addr_alloc(); + if (!filter_addr) { + nl_cache_free(addr_cache); + return -1; + } + rtnl_addr_set_ifindex(filter_addr, ifindex); + if (family) + rtnl_addr_set_family(filter_addr, family); + + //nm_log_dbg (log_domain, "(%s): syncing addresses (family %d)", iface, family); + + /* Walk through the cache, comparing the addresses already on + * the interface to the addresses in addrs. + */ + for (match = nl_cache_get_first(addr_cache); match; match + = nl_cache_get_next(match)) { + int buf_valid = -1; + match_addr = (struct rtnl_addr *) match; + + /* Skip addresses not on our interface */ + if (!nl_object_match_filter(match, (struct nl_object *) filter_addr)) + continue; + + if (addr) { + if (addr && nl_object_identical(match, (struct nl_object *) addr)) { + continue; + } + } + + nladdr = rtnl_addr_get_local(match_addr); + + /* Don't delete IPv6 link-local addresses; they don't belong to NM */ + if (rtnl_addr_get_family(match_addr) == AF_INET6) { + struct in6_addr *tmp; + + if (rtnl_addr_get_scope(match_addr) == RT_SCOPE_LINK) { + //nm_log_dbg (log_domain, "(%s): ignoring IPv6 link-local address", iface); + continue; + } + + tmp = (in6_addr*) nl_addr_get_binary_addr(nladdr); + if (inet_ntop(AF_INET6, tmp, buf, sizeof(buf))) + buf_valid = 0; + } else if (rtnl_addr_get_family(match_addr) == AF_INET) { + struct in_addr *tmp; + + tmp = (in_addr *) nl_addr_get_binary_addr(nladdr); + if (inet_ntop(AF_INET, tmp, buf, sizeof(buf))) + buf_valid = 0; + } + + if (buf_valid == 0) { + //nm_log_dbg (log_domain, "(%s): removing address '%s/%d'", + // iface, buf, nl_addr_get_prefixlen (nladdr)); + } + + /* Otherwise, match_addr should be removed from the interface. */ + err = rtnl_addr_delete(nlh, match_addr, 0); + if (err < 0) { + //nm_log_err (log_domain, "(%s): error %d returned from rtnl_addr_delete(): %s", + // iface, err, nl_geterror ()); + qDebug() << _tag << "error with delete addr"; + } + } + + rtnl_addr_put(filter_addr); + nl_cache_free(addr_cache); + + /* Now add the remaining new addresses */ + if (!addr) + return -1; + + struct in6_addr *in6tmp; + struct in_addr *in4tmp; + int buf_valid = -1; + + nladdr = rtnl_addr_get_local(addr); + if (rtnl_addr_get_family(addr) == AF_INET6) { + in6tmp = (in6_addr*) nl_addr_get_binary_addr(nladdr); + if (inet_ntop(AF_INET6, in6tmp, buf, sizeof(buf))) + buf_valid = 0; + } else if (rtnl_addr_get_family(addr) == AF_INET) { + in4tmp = (in_addr*) nl_addr_get_binary_addr(nladdr); + if (inet_ntop(AF_INET, in4tmp, buf, sizeof(buf))) + buf_valid = 0; + } + + if (buf_valid == 0) { + //nm_log_dbg (log_domain, "(%s): adding address '%s/%d'", + //iface, buf, nl_addr_get_prefixlen (nladdr)); + qDebug() << _tag << "buf valid adding addr"; + } + + err = rtnl_addr_add(nlh, addr, 0); + if (err < 0) { + //nm_log_err (log_domain, + // "(%s): error %d returned from rtnl_addr_add():\n%s", + // iface, err, nl_geterror ()); + qDebug() << _tag << "error with add addr"<< strerror(-err); + } + + rtnl_addr_put(addr); + + return err; +} + + + +/** + * This method writes a resolv.conf file. + * + * @param path + * path to the resolv.conf file. (in most cases: /etc/) + * @param ifname + * name of the interface + * @param + * addresses of the nameserver + * + * @return + * return 0 if success + * else -1 + */ +int NetworkManager::writeResolvConf(QString path, QString ifname, QList nameServer){ + + QFile file(path + "resolv.conf"); + if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qDebug() << _tag << "error couldn't open file:" << path; + return -1; + } + QTextStream out(&file); + out << "# Generated by networkdiscovery manual configuration for interface " + ifname +"\n"; + foreach(QString ns, nameServer ) { + out << "nameserver " + ns +"\n"; + } + + file.close(); + + return 0; +} + diff --git a/src/fbgui/networkmanager.h b/src/fbgui/networkmanager.h new file mode 100644 index 0000000..fbb8993 --- /dev/null +++ b/src/fbgui/networkmanager.h @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + */ + + + +#ifndef NETWORKMANAGER_H_ +#define NETWORKMANAGER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class NetworkManager: public QObject { +Q_OBJECT + +public: + NetworkManager(); + virtual ~NetworkManager(); + + int replaceDefaultRoute(QString ifname, QString gateway, int metric, + int af); + + int bringInterfaceUP(QString ifname); + int bringInterfaceDown(QString ifname); + + int ip4_setManualConfiguration(QString ifname, QString ipAddress, QString netmask, + QString broadcast, QString gateway, int metric, int af, QString pathToResolvConf, QList nameServer); + int ip4_configureInterface(QString ifname, QString ipAddress, + QString broadcast, QString netmask, int af); + + int ip6_addRoute(const char *iface, + const struct in6_addr *ip6_dest, int ip6_prefix, + const struct in6_addr *ip6_gateway, int metric, int mss); + int ip6_addAddress(struct ip6_addr* ip6Addr, const char *iface); + + int writeResolvConf(QString path, QString ifname, QList nameServer); + +private: + QString _tag; + int bringInterfaceUpDown(QString ifname, bool up); + int ip4_netmaskToPrefix(QString ipAddr, QString netmask); + + int sync_address(const char *iface, int ifindex, int family, + struct rtnl_addr *addr); + + struct rtnl_route* create_route (int iface_idx, int mss); + struct nl_addr* ip6AddrToNlAddr (const struct ip6_addr* ip6Addr); + int nlAddrToRtnlAddr (const struct ip6_addr* ip6Addr, struct rtnl_addr* addr); + struct rtnl_addr* ip6AddrToRtnlAddr(struct ip6_addr* ip6Addr); + + +}; + +#endif /* NETWORKMANAGER_H_ */ diff --git a/src/fbgui/sysinfo.cpp b/src/fbgui/sysinfo.cpp new file mode 100644 index 0000000..7d6ac92 --- /dev/null +++ b/src/fbgui/sysinfo.cpp @@ -0,0 +1,180 @@ +#include "sysinfo.h" + +// ------------------------------------------------------------------------------------------------ +/** + * A empty constructor. + */ +SysInfo::SysInfo() { +} +// ------------------------------------------------------------------------------------------------ +/** + * A empty destructor. + */ +SysInfo::~SysInfo() { +} +// ------------------------------------------------------------------------------------------------ +/** + * This method returns system informations. + * + * This method returns system informations according to the parameter. + * This method can be called from the JavascriptInterface class with the + * method JavascriptInterface::getSysInfo(const QString& info). + * + * @param infoName + * Is of type QString. Defines which method will be called. Possible values are: + * - mbserial + * - usb + * + * @return QString + * the output of the called method or "info_error" if an error occurred + * (e. g. invalid parameter). + * + * @see JavascriptInterface::getSysInfo(const QString& info) + */ +const QString SysInfo::getInfo(const QString& infoName) { + qxtLog->debug() << "[sysinfo] requested " << infoName; + if (infoName == QString("mbserial")) + return getMainboardSerial(); + else if (infoName == QString("usb")) + return getUsbVendorIdProductIdSerialNumber(); + /* unknown code */ + qxtLog->debug() << "[sysinfo] unknown requested"; + return "info_error"; +} +// ----------------------------------------------------------------------------------------------- +// Mainboard / USB Infos using libsysfs +// ----------------------------------------------------------------------------------------------- +/** + * This method returns the Mainboard Serial Number. + * + * This method returns the Mainboard Serial Number. The mainboard serial + * number is used as part of the data to compute the hardwarehash of the + * client machine. To call this method use the + * SysInfo::getInfo(const QString& infoName) method with + * the parameter "mbserial" + * + * @return QString + * the mainboard serial or "mainboard_serial_error" if an error occurred. + * + * @see fbgui::generatePOSTData() + * @see SysInfo::getInfo(const QString& infoName) + */ +const QString SysInfo::getMainboardSerial() { + QString out = ""; + struct sysfs_class_device *class_device = sysfs_open_class_device("dmi", + "id"); + struct dlist *attrlist = sysfs_get_classdev_attributes(class_device); + struct sysfs_device *device = sysfs_get_classdev_device(class_device); + + if (attrlist != NULL) { + struct sysfs_attribute *attr = NULL; + dlist_for_each_data(attrlist, attr, struct sysfs_attribute) { + QVariantMap a; + if(QString(attr->name) == QString("board_serial")) { + out = QString(attr->value); + } + } + qxtLog->debug() << "[sysinfo] Mainboard Serial: " + out; + return out; + } + qxtLog->debug() + << "[sysinfo] Mainboard Serial: attrlist is null! return: mainboard_serial_error"; + sysfs_close_class_device(class_device); + return "mainboard_serial_error"; +} +// ------------------------------------------------------------------------------------------------ +/** + * This method returns inforamtions about connected usb devices. + * + * This method returns the inforamtions about connected usb devices + * as a json formated string. + * Those informations are: + * - the vendor + * - the vendorID + * - the product + * - the productID + * - the manufacturer + * - the serial number + * To call this method use the SysInfo::getInfo(const QString& infoName) + * method with the parameter "usb" + * + * @return QString + * all above described informations as a json formated string or "error" + * if an error occurred. + * + * @see SysInfo::getInfo(const QString& infoName) + */ +const QString SysInfo::getUsbVendorIdProductIdSerialNumber() { + + QString tag = "[sysinfo] Usb Serial:"; + QString out = ""; + QVariantList list; + + libusb_device **devs; + libusb_context *ctx = NULL; //a libusb session + ssize_t cnt; //holding number of devices in list + int r = 1; + r = libusb_init(&ctx); + if (r < 0) { + qxtLog->debug() << tag + "failed to initialise libusb"; + return "error"; + } + cnt = libusb_get_device_list(ctx, &devs); //get the list of devices + if (cnt < 0) { + qxtLog->debug() << tag + "Get Device Error"; //there was an error + } + qxtLog->debug() << tag + cnt + " Devices in list."; //print total number of usb devices + ssize_t i; //for iterating through the list# + for (i = 0; i < cnt; i++) { + //printdev(devs[i]); //print specs of this device + QVariantMap infos; + libusb_device *dev = devs[i]; + libusb_device_descriptor desc; + int re = libusb_get_device_descriptor(dev, &desc); + if (re < 0) { + qxtLog->debug() << tag + "failed to get device descriptor"; + return "error"; + } + infos.insert("vendorId", desc.idVendor); + infos.insert("productId", desc.idProduct); + unsigned char string[256]; + libusb_device_handle *handle; + re = libusb_open(dev, &handle); + if (re != 0) { + qxtLog->debug() << tag + "failed to get handler / fail to open device"; + return "error"; + } + re = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, + string, sizeof(string)); + if (re < 0) { + qxtLog->debug() << tag + "failed to get SerialNumber"; + return "error"; + } + infos.insert("serialnumber", QString((const char *) string)); + re = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, + sizeof(string)); + if (re < 0) { + qxtLog->debug() << tag + "failed to get Product"; + return "error"; + } + infos.insert("product", QString((const char *) string)); + re = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, + string, sizeof(string)); + if (re < 0) { + qxtLog->debug() << tag + "failed to get Product"; + return "error"; + } + infos.insert("manuacturer", QString((const char *) string)); + + list << infos; + libusb_close(handle); + } + libusb_free_device_list(devs, 1); //free the list, unref the devices in it + libusb_exit(ctx); //close the session + + /* + QByteArray json = serializer.serialize(list); + qxtLog->debug() << tag + "json object: " + json; + return json; + */ +} diff --git a/src/fbgui/sysinfo.h b/src/fbgui/sysinfo.h new file mode 100644 index 0000000..c860cca --- /dev/null +++ b/src/fbgui/sysinfo.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010,2011 - RZ Uni Freiburg + * Copyright (c) 2010,2011 - OpenSLX Project + * + * This program/file is free software distributed under the GPL version 2. + * See http://openslx.org/COPYING + * + * If you have any feedback please consult http://openslx.org/feedback and + * send your feedback to feedback@openslx.org + * + * General information about OpenSLX can be found under http://openslx.org + * + * + * Helper class to get system information. + * + */ + +#ifndef SYSINFO_H +#define SYSINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sysfs/libsysfs.h" +#include +#ifdef __cplusplus +} +#endif + +#include "fbgui.h" +//#include + +class SysInfo { +public: + SysInfo(); + ~SysInfo(); + // public access, valid infoName: "mbserial", "usb" + const QString getInfo(const QString& infoName); + +private: + // private system information readers + const QString getMainboardSerial(); + const QString getUsbVendorIdProductIdSerialNumber(); + + // JSon testing + //QJson::Serializer serializer; +}; + +#endif // SYSTINFO_H diff --git a/src/html/background.png b/src/html/background.png deleted file mode 100644 index 7e374f9..0000000 Binary files a/src/html/background.png and /dev/null differ diff --git a/src/html/continueBoot.html b/src/html/continueBoot.html deleted file mode 100644 index 89020b7..0000000 --- a/src/html/continueBoot.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - -
    -
    -
    -

    Continue Boot

    -
    -
    - -
    - - - diff --git a/src/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/src/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png deleted file mode 100644 index 954e22d..0000000 Binary files a/src/html/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png and /dev/null differ diff --git a/src/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png b/src/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png deleted file mode 100644 index 64ece57..0000000 Binary files a/src/html/css/images/ui-bg_diagonals-thick_20_666666_40x40.png and /dev/null differ diff --git a/src/html/css/images/ui-bg_flat_10_000000_40x100.png b/src/html/css/images/ui-bg_flat_10_000000_40x100.png deleted file mode 100644 index abdc010..0000000 Binary files a/src/html/css/images/ui-bg_flat_10_000000_40x100.png and /dev/null differ diff --git a/src/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png b/src/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png deleted file mode 100644 index 9b383f4..0000000 Binary files a/src/html/css/images/ui-bg_glass_100_f6f6f6_1x400.png and /dev/null differ diff --git a/src/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png b/src/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png deleted file mode 100644 index a23baad..0000000 Binary files a/src/html/css/images/ui-bg_glass_100_fdf5ce_1x400.png and /dev/null differ diff --git a/src/html/css/images/ui-bg_glass_65_ffffff_1x400.png b/src/html/css/images/ui-bg_glass_65_ffffff_1x400.png deleted file mode 100644 index 42ccba2..0000000 Binary files a/src/html/css/images/ui-bg_glass_65_ffffff_1x400.png and /dev/null differ diff --git a/src/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png b/src/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png deleted file mode 100644 index 39d5824..0000000 Binary files a/src/html/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png and /dev/null differ diff --git a/src/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/src/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png deleted file mode 100644 index f127367..0000000 Binary files a/src/html/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png and /dev/null differ diff --git a/src/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png b/src/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png deleted file mode 100644 index 359397a..0000000 Binary files a/src/html/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png and /dev/null differ diff --git a/src/html/css/images/ui-icons_222222_256x240.png b/src/html/css/images/ui-icons_222222_256x240.png deleted file mode 100644 index b273ff1..0000000 Binary files a/src/html/css/images/ui-icons_222222_256x240.png and /dev/null differ diff --git a/src/html/css/images/ui-icons_228ef1_256x240.png b/src/html/css/images/ui-icons_228ef1_256x240.png deleted file mode 100644 index a641a37..0000000 Binary files a/src/html/css/images/ui-icons_228ef1_256x240.png and /dev/null differ diff --git a/src/html/css/images/ui-icons_ef8c08_256x240.png b/src/html/css/images/ui-icons_ef8c08_256x240.png deleted file mode 100644 index 85e63e9..0000000 Binary files a/src/html/css/images/ui-icons_ef8c08_256x240.png and /dev/null differ diff --git a/src/html/css/images/ui-icons_ffd27a_256x240.png b/src/html/css/images/ui-icons_ffd27a_256x240.png deleted file mode 100644 index e117eff..0000000 Binary files a/src/html/css/images/ui-icons_ffd27a_256x240.png and /dev/null differ diff --git a/src/html/css/images/ui-icons_ffffff_256x240.png b/src/html/css/images/ui-icons_ffffff_256x240.png deleted file mode 100644 index 42f8f99..0000000 Binary files a/src/html/css/images/ui-icons_ffffff_256x240.png and /dev/null differ diff --git a/src/html/css/jquery-ui-1.8.16.css b/src/html/css/jquery-ui-1.8.16.css deleted file mode 100644 index 5547c7b..0000000 --- a/src/html/css/jquery-ui-1.8.16.css +++ /dev/null @@ -1,568 +0,0 @@ -/* - * jQuery UI CSS Framework 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - */ - -/* Layout helpers -----------------------------------*/ -.ui-helper-hidden { display: none; } -.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } -.ui-helper-clearfix { display: inline-block; } -/* required comment for clearfix to work in Opera \*/ -* html .ui-helper-clearfix { height:1%; } -.ui-helper-clearfix { display:block; } -/* end clearfix */ -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } - - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { cursor: default !important; } - - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } - - -/* Misc visuals -----------------------------------*/ - -/* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } - - -/* - * jQuery UI CSS Framework 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - * - * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px - */ - - -/* Component containers -----------------------------------*/ -.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } -.ui-widget .ui-widget { font-size: 1em; } -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } -.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } -.ui-widget-content a { color: #333333; } -.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } -.ui-widget-header a { color: #ffffff; } - -/* Interaction states -----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } -.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } -.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } -.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } -.ui-widget :active { outline: none; } - -/* Interaction Cues -----------------------------------*/ -.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } -.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } -.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } -.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } -.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } -.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } -.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } -.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } -.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } -.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } -.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } -.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } - -/* positioning */ -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } -.ui-icon-triangle-1-n { background-position: 0 -16px; } -.ui-icon-triangle-1-ne { background-position: -16px -16px; } -.ui-icon-triangle-1-e { background-position: -32px -16px; } -.ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } -.ui-icon-triangle-1-sw { background-position: -80px -16px; } -.ui-icon-triangle-1-w { background-position: -96px -16px; } -.ui-icon-triangle-1-nw { background-position: -112px -16px; } -.ui-icon-triangle-2-n-s { background-position: -128px -16px; } -.ui-icon-triangle-2-e-w { background-position: -144px -16px; } -.ui-icon-arrow-1-n { background-position: 0 -32px; } -.ui-icon-arrow-1-ne { background-position: -16px -32px; } -.ui-icon-arrow-1-e { background-position: -32px -32px; } -.ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } -.ui-icon-arrow-1-sw { background-position: -80px -32px; } -.ui-icon-arrow-1-w { background-position: -96px -32px; } -.ui-icon-arrow-1-nw { background-position: -112px -32px; } -.ui-icon-arrow-2-n-s { background-position: -128px -32px; } -.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } -.ui-icon-arrow-2-e-w { background-position: -160px -32px; } -.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } -.ui-icon-arrowstop-1-n { background-position: -192px -32px; } -.ui-icon-arrowstop-1-e { background-position: -208px -32px; } -.ui-icon-arrowstop-1-s { background-position: -224px -32px; } -.ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } -.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } -.ui-icon-arrowthick-1-e { background-position: -32px -48px; } -.ui-icon-arrowthick-1-se { background-position: -48px -48px; } -.ui-icon-arrowthick-1-s { background-position: -64px -48px; } -.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } -.ui-icon-arrowthick-1-w { background-position: -96px -48px; } -.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } -.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } -.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } -.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } -.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } -.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } -.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } -.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } -.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } -.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } -.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } -.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } -.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } -.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } -.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } -.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } -.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } -.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } -.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } -.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } -.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } -.ui-icon-arrow-4 { background-position: 0 -80px; } -.ui-icon-arrow-4-diag { background-position: -16px -80px; } -.ui-icon-extlink { background-position: -32px -80px; } -.ui-icon-newwin { background-position: -48px -80px; } -.ui-icon-refresh { background-position: -64px -80px; } -.ui-icon-shuffle { background-position: -80px -80px; } -.ui-icon-transfer-e-w { background-position: -96px -80px; } -.ui-icon-transferthick-e-w { background-position: -112px -80px; } -.ui-icon-folder-collapsed { background-position: 0 -96px; } -.ui-icon-folder-open { background-position: -16px -96px; } -.ui-icon-document { background-position: -32px -96px; } -.ui-icon-document-b { background-position: -48px -96px; } -.ui-icon-note { background-position: -64px -96px; } -.ui-icon-mail-closed { background-position: -80px -96px; } -.ui-icon-mail-open { background-position: -96px -96px; } -.ui-icon-suitcase { background-position: -112px -96px; } -.ui-icon-comment { background-position: -128px -96px; } -.ui-icon-person { background-position: -144px -96px; } -.ui-icon-print { background-position: -160px -96px; } -.ui-icon-trash { background-position: -176px -96px; } -.ui-icon-locked { background-position: -192px -96px; } -.ui-icon-unlocked { background-position: -208px -96px; } -.ui-icon-bookmark { background-position: -224px -96px; } -.ui-icon-tag { background-position: -240px -96px; } -.ui-icon-home { background-position: 0 -112px; } -.ui-icon-flag { background-position: -16px -112px; } -.ui-icon-calendar { background-position: -32px -112px; } -.ui-icon-cart { background-position: -48px -112px; } -.ui-icon-pencil { background-position: -64px -112px; } -.ui-icon-clock { background-position: -80px -112px; } -.ui-icon-disk { background-position: -96px -112px; } -.ui-icon-calculator { background-position: -112px -112px; } -.ui-icon-zoomin { background-position: -128px -112px; } -.ui-icon-zoomout { background-position: -144px -112px; } -.ui-icon-search { background-position: -160px -112px; } -.ui-icon-wrench { background-position: -176px -112px; } -.ui-icon-gear { background-position: -192px -112px; } -.ui-icon-heart { background-position: -208px -112px; } -.ui-icon-star { background-position: -224px -112px; } -.ui-icon-link { background-position: -240px -112px; } -.ui-icon-cancel { background-position: 0 -128px; } -.ui-icon-plus { background-position: -16px -128px; } -.ui-icon-plusthick { background-position: -32px -128px; } -.ui-icon-minus { background-position: -48px -128px; } -.ui-icon-minusthick { background-position: -64px -128px; } -.ui-icon-close { background-position: -80px -128px; } -.ui-icon-closethick { background-position: -96px -128px; } -.ui-icon-key { background-position: -112px -128px; } -.ui-icon-lightbulb { background-position: -128px -128px; } -.ui-icon-scissors { background-position: -144px -128px; } -.ui-icon-clipboard { background-position: -160px -128px; } -.ui-icon-copy { background-position: -176px -128px; } -.ui-icon-contact { background-position: -192px -128px; } -.ui-icon-image { background-position: -208px -128px; } -.ui-icon-video { background-position: -224px -128px; } -.ui-icon-script { background-position: -240px -128px; } -.ui-icon-alert { background-position: 0 -144px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-notice { background-position: -32px -144px; } -.ui-icon-help { background-position: -48px -144px; } -.ui-icon-check { background-position: -64px -144px; } -.ui-icon-bullet { background-position: -80px -144px; } -.ui-icon-radio-off { background-position: -96px -144px; } -.ui-icon-radio-on { background-position: -112px -144px; } -.ui-icon-pin-w { background-position: -128px -144px; } -.ui-icon-pin-s { background-position: -144px -144px; } -.ui-icon-play { background-position: 0 -160px; } -.ui-icon-pause { background-position: -16px -160px; } -.ui-icon-seek-next { background-position: -32px -160px; } -.ui-icon-seek-prev { background-position: -48px -160px; } -.ui-icon-seek-end { background-position: -64px -160px; } -.ui-icon-seek-start { background-position: -80px -160px; } -/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ -.ui-icon-seek-first { background-position: -80px -160px; } -.ui-icon-stop { background-position: -96px -160px; } -.ui-icon-eject { background-position: -112px -160px; } -.ui-icon-volume-off { background-position: -128px -160px; } -.ui-icon-volume-on { background-position: -144px -160px; } -.ui-icon-power { background-position: 0 -176px; } -.ui-icon-signal-diag { background-position: -16px -176px; } -.ui-icon-signal { background-position: -32px -176px; } -.ui-icon-battery-0 { background-position: -48px -176px; } -.ui-icon-battery-1 { background-position: -64px -176px; } -.ui-icon-battery-2 { background-position: -80px -176px; } -.ui-icon-battery-3 { background-position: -96px -176px; } -.ui-icon-circle-plus { background-position: 0 -192px; } -.ui-icon-circle-minus { background-position: -16px -192px; } -.ui-icon-circle-close { background-position: -32px -192px; } -.ui-icon-circle-triangle-e { background-position: -48px -192px; } -.ui-icon-circle-triangle-s { background-position: -64px -192px; } -.ui-icon-circle-triangle-w { background-position: -80px -192px; } -.ui-icon-circle-triangle-n { background-position: -96px -192px; } -.ui-icon-circle-arrow-e { background-position: -112px -192px; } -.ui-icon-circle-arrow-s { background-position: -128px -192px; } -.ui-icon-circle-arrow-w { background-position: -144px -192px; } -.ui-icon-circle-arrow-n { background-position: -160px -192px; } -.ui-icon-circle-zoomin { background-position: -176px -192px; } -.ui-icon-circle-zoomout { background-position: -192px -192px; } -.ui-icon-circle-check { background-position: -208px -192px; } -.ui-icon-circlesmall-plus { background-position: 0 -208px; } -.ui-icon-circlesmall-minus { background-position: -16px -208px; } -.ui-icon-circlesmall-close { background-position: -32px -208px; } -.ui-icon-squaresmall-plus { background-position: -48px -208px; } -.ui-icon-squaresmall-minus { background-position: -64px -208px; } -.ui-icon-squaresmall-close { background-position: -80px -208px; } -.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } -.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } -.ui-icon-grip-solid-vertical { background-position: -32px -224px; } -.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } -.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } -.ui-icon-grip-diagonal-se { background-position: -80px -224px; } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } -.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } - -/* Overlays */ -.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } -.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* - * jQuery UI Resizable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Resizable#theming - */ -.ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* - * jQuery UI Selectable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectable#theming - */ -.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } -/* - * jQuery UI Accordion 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Accordion#theming - */ -/* IE/Win - Fix animation bug - #4615 */ -.ui-accordion { width: 100%; } -.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } -.ui-accordion .ui-accordion-li-fix { display: inline; } -.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } -.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } -.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } -.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } -.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } -.ui-accordion .ui-accordion-content-active { display: block; } -/* - * jQuery UI Autocomplete 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete#theming - */ -.ui-autocomplete { position: absolute; cursor: default; } - -/* workarounds */ -* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -/* - * jQuery UI Menu 1.8.16 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu#theming - */ -.ui-menu { - list-style:none; - padding: 2px; - margin: 0; - display:block; - float: left; -} -.ui-menu .ui-menu { - margin-top: -3px; -} -.ui-menu .ui-menu-item { - margin:0; - padding: 0; - zoom: 1; - float: left; - clear: left; - width: 100%; -} -.ui-menu .ui-menu-item a { - text-decoration:none; - display:block; - padding:.2em .4em; - line-height:1.5; - zoom:1; -} -.ui-menu .ui-menu-item a.ui-state-hover, -.ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; -} -/* - * jQuery UI Button 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Button#theming - */ -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ -.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ -button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } - -/*button text element */ -.ui-button .ui-button-text { display: block; line-height: 1.4; } -.ui-button-text-only .ui-button-text { padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } -.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } -.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } -.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { padding: .4em 1em; } - -/*button icon element(s) */ -.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } -.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } -.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } - -/*button sets*/ -.ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } - -/* workarounds */ -button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ -/* - * jQuery UI Dialog 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog#theming - */ -.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } -.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } -.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } -.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } -.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } -.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } -.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } -.ui-draggable .ui-dialog-titlebar { cursor: move; } -/* - * jQuery UI Slider 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Slider#theming - */ -.ui-slider { position: relative; text-align: left; } -.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } -.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } - -.ui-slider-horizontal { height: .8em; } -.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } -.ui-slider-horizontal .ui-slider-range-min { left: 0; } -.ui-slider-horizontal .ui-slider-range-max { right: 0; } - -.ui-slider-vertical { width: .8em; height: 100px; } -.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } -.ui-slider-vertical .ui-slider-range-max { top: 0; }/* - * jQuery UI Tabs 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs#theming - */ -.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ -.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } -.ui-tabs .ui-tabs-hide { display: none !important; } -/* - * jQuery UI Datepicker 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Datepicker#theming - */ -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } -.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } -.ui-datepicker .ui-datepicker-prev-hover { left:1px; } -.ui-datepicker .ui-datepicker-next-hover { right:1px; } -.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } -.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } -.ui-datepicker td { border: 0; padding: 1px; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } -.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } - -/* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { width:auto; } -.ui-datepicker-multi .ui-datepicker-group { float:left; } -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } -.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } - -/* RTL support */ -.ui-datepicker-rtl { direction: rtl; } -.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } -.ui-datepicker-rtl .ui-datepicker-group { float:right; } -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - display: none; /*sorry for IE5*/ - display/**/: block; /*sorry for IE5*/ - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -}/* - * jQuery UI Progressbar 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar#theming - */ -.ui-progressbar { height:2em; text-align: left; } -.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/src/html/images/loading.gif b/src/html/images/loading.gif deleted file mode 100644 index cbe59fb..0000000 Binary files a/src/html/images/loading.gif and /dev/null differ diff --git a/src/html/js/jquery-1.6.4.min.js b/src/html/js/jquery-1.6.4.min.js deleted file mode 100644 index 628ed9b..0000000 --- a/src/html/js/jquery-1.6.4.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */ -(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
    a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
    ";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/src/html/js/jquery-ui-1.8.16.min.js b/src/html/js/jquery-ui-1.8.16.min.js deleted file mode 100644 index 14c9064..0000000 --- a/src/html/js/jquery-ui-1.8.16.min.js +++ /dev/null @@ -1,791 +0,0 @@ -/*! - * jQuery UI 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.16", -keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({propAttr:c.fn.prop||c.fn.attr,_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d= -this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this, -"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart": -"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight, -outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a, -"tabindex"),d=isNaN(b);return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&& -a.element[0].parentNode)for(var e=0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= -false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -;/* - * jQuery UI Position 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Position - */ -(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, -left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= -k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= -m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= -d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= -a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), -g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); -;/* - * jQuery UI Draggable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== -"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= -this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;if(b.iframeFix)d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('
    ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options; -this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true}, -_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b= -false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, -10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle|| -!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&& -a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= -this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"), -10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), -10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, -(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!= -"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"), -10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+ -this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&& -!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.leftg[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.topg[3])?h:!(h-this.offset.click.topg[2])?e:!(e-this.offset.click.left=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e=j&&f<=l||h>=j&&h<=l||fl)&&(e>= -i&&e<=k||g>=i&&g<=k||ek);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), -top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= -this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", -nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor== -String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection(); -this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){if(!a.disabled){e(this).removeClass("ui-resizable-autohide");b._handles.show()}},function(){if(!a.disabled)if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy(); -var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a= -false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"}); -this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff= -{width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis]; -if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false}, -_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f, -{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(b){var a=this.options,c,d,f;a={minWidth:k(a.minWidth)?a.minWidth:0,maxWidth:k(a.maxWidth)?a.maxWidth:Infinity,minHeight:k(a.minHeight)?a.minHeight:0,maxHeight:k(a.maxHeight)?a.maxHeight: -Infinity};if(this._aspectRatio||b){b=a.minHeight*this.aspectRatio;d=a.minWidth/this.aspectRatio;c=a.maxHeight*this.aspectRatio;f=a.maxWidth/this.aspectRatio;if(b>a.minWidth)a.minWidth=b;if(d>a.minHeight)a.minHeight=d;if(cb.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&l)b.left=i-a.minWidth;if(d&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left= -null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+ -a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+ -c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]); -b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.16"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(), -10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top- -f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var l=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:l.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(l.css("position"))){c._revertToRelativePosition=true;l.css({position:"absolute",top:"auto",left:"auto"})}l.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType? -e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a= -e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing, -step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement= -e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset; -var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left: -a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top- -d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition, -f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25, -display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b= -e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height= -d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery); -;/* - * jQuery UI Selectable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"), -selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("
    ")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX, -c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting", -c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d= -this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.righti||a.bottomb&&a.rightg&&a.bottom *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable"); -this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a=== -"disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&& -!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top, -left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]}; -this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!= -document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a); -return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0], -e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset(); -c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"): -this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null, -dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")}, -toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+jg&&b+la[this.floating?"width":"height"]?j:g0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith(); -if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), -this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b= -this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f= -d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")|| -0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out", -a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h- -f)this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g- -this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.topthis.containment[3])?g:!(g-this.offset.click.topthis.containment[2])?f:!(f-this.offset.click.left=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this, -this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop", -a,this._uiHash());for(e=0;e li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"); -a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); -if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion", -function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a= -this.options;if(a.icons){c("").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"); -this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons(); -b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target); -a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+ -c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options; -if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header); -if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(), -e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight|| -e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false", -"aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.16", -animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/); -f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide", -paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery); -;/* - * jQuery UI Autocomplete 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.propAttr("readOnly"))){g= -false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!= -a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)}; -this.menu=d("
      ").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&& -a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); -d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&& -b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source= -this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length").data("item.autocomplete",b).append(d("").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, -"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery); -(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", --1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); -this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b, -this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.first()?":last":":first"))},hasScroll:function(){return this.element.height()").addClass("ui-button-text").html(this.options.label).appendTo(a.empty()).text(),e=this.options.icons,f=e.primary&&e.secondary,d=[];if(e.primary||e.secondary){if(this.options.text)d.push("ui-button-text-icon"+(f?"s":e.primary?"-primary":"-secondary"));e.primary&&a.prepend("");e.secondary&&a.append("");if(!this.options.text){d.push(f?"ui-button-icons-only": -"ui-button-icon-only");this.hasTitle||a.attr("title",c)}}else d.push("ui-button-text-only");a.addClass(d.join(" "))}}});b.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(a,c){a==="disabled"&&this.buttons.button("option",a,c);b.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var a=this.element.css("direction")=== -"ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(a?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(a?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"); -b.Widget.prototype.destroy.call(this)}})})(jQuery); -;/* - * jQuery UI Dialog 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, -position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("
      ")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ -b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&!i.isDefaultPrevented()&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("
      ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g), -h=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("").addClass("ui-dialog-title").attr("id", -e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); -a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!== -b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()};c.ui.dialog.maxZ+=1; -d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target=== -f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("
      ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("
      ").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a, -function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", -handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition, -originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize", -f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "): -[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f); -if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"): -e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a= -this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height- -b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "), -create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&& -c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(b.range==="min"||b.range==="max"?" ui-slider-range-"+b.range:""))}for(var j=c.length;j"); -this.handles=c.add(d(e.join("")).appendTo(a.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle", -g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!a.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");i=a._start(g,l);if(i===false)return}break}m=a.options.step;i=a.options.values&&a.options.values.length? -(h=a.values(l)):(h=a.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=a._valueMin();break;case d.ui.keyCode.END:h=a._valueMax();break;case d.ui.keyCode.PAGE_UP:h=a._trimAlignValue(i+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=a._trimAlignValue(i-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===a._valueMax())return;h=a._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===a._valueMin())return;h=a._trimAlignValue(i- -m);break}a._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(g,k);a._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(a){var b=this.options,c,f,e,j,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(b.range===true&&this.values(1)===b.min){g+=1;e=d(this.handles[g])}if(this._start(a,g)===false)return false; -this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();b=e.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-e.width()/2,top:a.pageY-b.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b= -this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b= -this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b); -c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var f;if(this.options.values&&this.options.values.length){f=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>f||b===1&&c1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a= -this.options.range,b=this.options,c=this,f=!this._animateOff?b.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({width:e- -g+"%"},{queue:false,duration:b.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:b.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[f?"animate":"css"]({width:e+"%"}, -b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.16"})})(jQuery); -;/* - * jQuery UI Tabs 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
      ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
    • #{label}
    • "},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& -e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= -d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| -(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); -this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= -this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); -if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); -this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ -g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", -function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; -this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= --1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; -d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= -d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, -e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); -j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); -if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, -this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, -load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, -"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, -url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.16"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k'))}function N(a){return a.bind("mouseout", -function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); -b.addClass("ui-state-hover");b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.16"}});var B=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv}, -setDefaults:function(a){H(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g, -"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('
      '))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker", -function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b);b.settings.disabled&&this._disableDatepicker(a)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d(''+c+"");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c== -"focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('').addClass(this._triggerClass).html(f==""?c:d("").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker(): -d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;gh){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a, -b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.settings.disabled&&this._disableDatepicker(a);b.dpDiv.css("display","block")}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+= -1;this._dialogInput=d('');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/ -2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b= -d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e= -a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a, -"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f== -a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input", -a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c=d.datepicker._get(b,"beforeShow");c=c?c.apply(a,[a,b]):{};if(c!==false){H(b.settings,c);b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value= -"";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b); -c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing= -true;d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv);J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}); -a.dpDiv.find("."+this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&& -!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(), -h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b= -this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b); -this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, -_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"): -0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e["selected"+(c=="M"? -"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a); -this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField"); -if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"? -b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=A+1-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd", -COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames: -null)||this._defaults.monthNames;var i=function(o){(o=k+1 -12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&& -a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay? -new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&nn;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a)); -n=this._canAdjustMonth(a,-1,m,g)?''+n+"":f?"":''+n+"";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m, -g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?''+s+"":f?"":''+s+"";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&& -a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'":"";e=e?'
      '+(c?h:"")+(this._isInRange(a,s)?'":"")+(c?"":h)+"
      ":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),A=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='
      '+(/all|left/.test(t)&& -x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,A,v)+'
      ';var z=j?'":"";for(t=0;t<7;t++){var r=(t+h)%7;z+="=5?' class="ui-datepicker-week-end"':"")+'>'+q[r]+""}y+=z+"";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay, -z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q";var R=!j?"":'";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&ro;R+='";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+""}g++;if(g>11){g=0;m++}y+="
      '+this._get(a,"weekHeader")+"
      '+this._get(a,"calculateWeek")(r)+""+(F&&!D?" ":L?''+ -r.getDate()+"":''+r.getDate()+"")+"
      "+(l?""+(i[0]>0&&G==i[1]-1?'
      ':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'': -"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='
      ',o="";if(h||!j)o+=''+i[b]+"";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+=''+c+"";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b, -e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="
      ";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+ -(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&ba?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input? -a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c, -e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a, -"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this; -if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a== -"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.16";window["DP_jQuery_"+B]=d})(jQuery); -;/* - * jQuery UI Progressbar 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("
      ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); -this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* -this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.16"})})(jQuery); -;/* - * jQuery UI Effects 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/ - */ -jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], -16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, -a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= -a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", -"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, -0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, -211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, -d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; -f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, -[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.16",save:function(c,a){for(var b=0;b").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}), -d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement; -if(c.parent().is(".ui-effects-wrapper")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)}); -return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this, -arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/ -2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b, -d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c, -a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b, -d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ -e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); -;/* - * jQuery UI Effects Fade 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Fold 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], -10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); -;/* - * jQuery UI Effects Highlight 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& -this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Pulsate 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ -(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); -b.dequeue()})})}})(jQuery); -; \ No newline at end of file diff --git a/src/html/js/networkDiscovery.js b/src/html/js/networkDiscovery.js deleted file mode 100644 index 2aaea11..0000000 --- a/src/html/js/networkDiscovery.js +++ /dev/null @@ -1,278 +0,0 @@ -var hideProgressIndicator = function () { - $("#ajaxBusy").hide(); -}; - - - -var updateTips = function ( t ) { - $( ".validateTips" ) - .text( t ) - .addClass( "ui-state-highlight" ); - setTimeout( - function() { - $( ".validateTips" ).removeClass( "ui-state-highlight", 1500 ); - }, - 500 ); -}; - - - -var checkLength = function ( o, n, min, max ) { - if ( o.val().length > max || o.val().length < min ) { - o.addClass( "ui-state-error" ); - updateTips( "Length of " + n + " must be between " + - min + " and " + max + "." ); - return false; - } else { - return true; - } -}; - - - -var checkRegexp = function ( o, regexp, n ) { - if ( !( regexp.test( o.val() ) ) ) { - o.addClass( "ui-state-error" ); - updateTips( n ); - return false; - } else { - return true; - } -}; - - - -var showLog = function (t) { - $("#nd_show_log_msg").html(t); - //$("#nd_show_log_msg").attr('readonly','readonly'); - $('#nd_show_log_dialog').resizable("enable"); - $("#nd_show_log_dialog").dialog( - { buttons: { "Cancel": function() { - $(this).dialog("close");}}, - minWidth: 600, - maxHeight: 400, - modal: true, - draggable: false, - closeOnEscape: false, - open: function(event, ui) { - $(this).css({'max-height': 400, 'overflow-y': 'auto'}); - }, - }); -}; - - - -var getInterfaceConfOnChange = function (i) { - var n = i.options[i.selectedIndex].text; - var jsonObj = fbgui.getInterfaceConf(n); - if (!jQuery.isEmptyObject(jsonObj)) { - $("#ipaddr").val(jsonObj.ipaddr); - $("#netmask").val(jsonObj.netmask); - $("#broadcast").val(jsonObj.broadcast); - $("#gateway").val(jsonObj.gateway); - $("#dns").val(jsonObj.dns); - } - -}; - - - -var getInterfaceConf = function (i) { - var jsonObj = fbgui.getInterfaceConf(i); - if (!jQuery.isEmptyObject(jsonObj)) { - $("#ipaddr").val(jsonObj.ipaddr); - $("#netmask").val(jsonObj.netmask); - $("#broadcast").val(jsonObj.broadcast); - $("#gateway").val(jsonObj.gateway); - $("#dns").val(jsonObj.dns); - } - -}; - - - -var ip4_manualConfigurationDialog = function () { - var jsonArr = fbgui.getManualConfInterfaces(); - if(jsonArr == "") { - var c = "

      Have not found usable interfaces for manual configuration

      "; - $("#nd_manual_configuration_dialog").html(c); - $("#nd_manual_configuration_dialog").dialog( - { buttons: { "Cancel": function() { - $(this).dialog("close");}}, - minWidth: 450, - modal: true, - resizable: false, - draggable: false, - open: function(event, ui) { $(".ui-dialog-titlebar-close").hide();} - }); - - } else { - var c = ""; - $("#nd_mc_ifname").html(c); - - var ifname = $("#nd_mc_ifname_select :selected").text(), - ipaddr = $("#ipaddr"), - netmask = $("#netmask"), - broadcast = $("#broadcast"), - gateway = $("#gateway"), - dns = $("#dns"), - allFields = $([]).add(ipaddr).add(netmask).add(broadcast).add(gateway).add(dns); - - getInterfaceConf(ifname); - - $("#nd_manual_configuration_dialog").dialog( - { buttons: { "Cancel": function() { - $(this).dialog("close");}, - "Continue": function() { - var bValid = true; - allFields.removeClass("ui-state-error"); - - bValid = bValid && checkLength(ipaddr, "IP-Address", 7, 15); - bValid = bValid && checkLength(netmask, "Netmask Address", 7, 15); - bValid = bValid && checkLength(broadcast, "Broadcast Address", 7, 15); - bValid = bValid && checkLength(gateway, "Gateway Address", 7, 15); - bValid = bValid && checkLength(dns, "DNS Address", 7, 15); - - bValid = bValid && checkRegexp(ipaddr, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 192.168.1.2 (max value is 255)"); - bValid = bValid && checkRegexp(netmask, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 255.255.255.0 (max value is 255)"); - bValid = bValid && checkRegexp(broadcast, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 192.168.1.255 (max value is 255)"); - bValid = bValid && checkRegexp(gateway, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 192.168.1.254 (max value is 255)"); - bValid = bValid && checkRegexp(dns, /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/, "Is not a valid IP-Address! Format has to be e.g.: 192.168.1.111 (max value is 255)"); - - if (bValid) { - // put variables into a json object - // send to qt networkdiscovery - var o = {"ifname" : ifname, - "ipaddr" : ipaddr.val(), - "netmask" : netmask.val(), - "broadcast" : broadcast.val(), - "gateway" : gateway.val(), - "dns" : dns.val() } - try { - fbgui.ip4_setManualConfiguration(o); - } catch (e) { - fbgui.notifyCall(e); - } - $(this).dialog("close"); - } } - } , - minWidth: 450, - modal: true, - resizable: false, - draggable: false, - closeOnEscape: false, - close: function() {allFields.val("").removeClass("ui-state-error");}, - open: function(event, ui) { $(".ui-dialog-titlebar-close").hide();} - }); - } -}; - - - -var abortBootDialog = function (m) { - fbgui.notifyCall("abortBootDialog"); - $("#nd_abort_boot_msg").html(m); - $("#nd_abort_boot_dialog").dialog( - { buttons: { "Manual Configure": function() { - ip4_manualConfigurationDialog();}, - "Show Log": function() { - var text = fbgui.readLogFile(); - showLog(text);}, - "Restart": function() {fbgui.restartSystem(); - $(this).dialog("close"); }, - "Shut Down": function() { fbgui.shutDownSystem(); - $(this).dialog("close"); }, - "Try Again": function() {fbgui.tryAgain(); - $(this).dialog("close"); } - } , - minWidth: 450, - modal: true, - resizable: false, - draggable: false, - closeOnEscape: false, - open: function(event, ui) { $(".ui-dialog-titlebar-close").hide();} - }); -}; - - - -var chooseInterfaceDialog = function (i) { - var cb = ""+ - ""; - - $("#nd_choose_interface_msg").html(cb); - $("#nd_choose_interface_dialog").dialog( - { buttons: { "Manual Configure": function() { - ip4_manualConfigurationDialog();}, - "Show Log": function() { - var text = fbgui.readLogFile(); - showLog(text);}, - "Restart": function() {fbgui.restartSystem(); - $(this).dialog("close"); }, - "Shut Down": function() { fbgui.shutDownSystem(); - $(this).dialog("close"); }, - "Continue": function() { - var ifName = $("#nd_ifName_select :selected").text(); - fbgui.continueBoot(ifName); - $(this).dialog("close"); - } - } , - minWidth: 550, - modal: true, - resizable: false, - draggable: false, - closeOnEscape: false, - open: function(event, ui) { $(".ui-dialog-titlebar-close").hide();} - }); -} - - - -var updateStatus = function (s){ - $("#nd_status").html(s); -}; - - - -var updateIfProgressBar = function (i, p){ - if (p >= 0 && p <= 100){ - $("#"+i+"_progress").progressbar({ value: p }); - }else{ - $("#"+i+"_progress").progressbar({ value: 0 }); - } -}; - - - -var updateIfStatus = function(i, s){ - $("#"+i+"_status").html(s); -}; - - - -var addInterface = function (i){ - hideProgressIndicator(); - $("#nd_progress_container").append( - "
      "+ - " Interface: " +i+ - " Start DHCP " + - "
      "+ - "
      " - ); - //$("#"+i+"_progress").progressbar({ value: 33 }); -}; - - diff --git a/src/html/loadsystem.css b/src/html/loadsystem.css deleted file mode 100644 index 6a6e64f..0000000 --- a/src/html/loadsystem.css +++ /dev/null @@ -1,90 +0,0 @@ -html,body{ - height:100%; -} -body{ - margin:0; - padding:0; - background-color:black; - /* - background-image:url('background.png'); - background-repeat:no-repeat; - */ - background-size:100%; -} -#message{ - position:relative; - font-size:90%; - top:40%; -} -h1, p{ - text-align:center; - color:white; -} -* html{ - height:100%; -} -/* position the bars and balls correctly (rotate them and translate them outward)*/ -.bar1 { - -moz-transform:rotate(0deg) translate(0, -40px); - -webkit-transform:rotate(0deg) translate(0, -40px);opacity:0.12; -} -.bar2 { - -moz-transform:rotate(45deg) translate(0, -40px); - -webkit-transform:rotate(45deg) translate(0, -40px);opacity:0.25; -} -.bar3 { - -moz-transform:rotate(90deg) translate(0, -40px); - -webkit-transform:rotate(90deg) translate(0, -40px);opacity:0.37; -} -.bar4 { - -moz-transform:rotate(135deg) translate(0, -40px); - -webkit-transform:rotate(135deg) translate(0, -40px);opacity:0.50; -} -.bar5 { - -moz-transform:rotate(180deg) translate(0, -40px); - -webkit-transform:rotate(180deg) translate(0, -40px);opacity:0.62; -} -.bar6 { - -moz-transform:rotate(225deg) translate(0, -40px); - -webkit-transform:rotate(225deg) translate(0, -40px);opacity:0.75; -} -.bar7 { - -moz-transform:rotate(270deg) translate(0, -40px); - -webkit-transform:rotate(270deg) translate(0, -40px);opacity:0.87; -} -.bar8 { - -moz-transform:rotate(315deg) translate(0, -40px); - -webkit-transform:rotate(315deg) translate(0, -40px);opacity:1; -} -#div4 { - position:absolute; - left:50%; - top:50%; - margin-left:-50px; - margin-top:-50px; - width:100px; - height:100px; - -moz-border-radius:100px; - -webkit-border-radius:100px; - -moz-transform:scale(0.5); - -webkit-transform:scale(0.5); - -webkit-animation-name: rotateThis; - -webkit-animation-duration:2s; - -webkit-animation-iteration-count:infinite; - -webkit-animation-timing-function:linear; -} -#div4 div { - width:20px; - height:20px; - background:#fff; - -moz-border-radius:40px; - -webkit-border-radius:40px; - position:absolute; - left:40px; - top:40px; -} -/* add a shadow to the first */ -#div4 div { - -moz-box-shadow:black 0 0 4px; - -webkit-box-shadow:black 0 0 4px; -} diff --git a/src/html/loadsystem.html b/src/html/loadsystem.html deleted file mode 100644 index 838423e..0000000 --- a/src/html/loadsystem.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - -
      -

      Loading system, please wait...

      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - - diff --git a/src/html/networkdiscovery.css b/src/html/networkdiscovery.css deleted file mode 100644 index cf4121d..0000000 --- a/src/html/networkdiscovery.css +++ /dev/null @@ -1,90 +0,0 @@ -html,body{ - height:100%; -} - -label, input { - display:block -} - -input.text { - margin-bottom:12px; - width:95%; - padding: .4em; -} - -fieldset { - padding:0; - border:0; - margin-top:25px; -} - -.validateTips { - border:1px solid transparent; - padding: 0.3; -} - -body{ - margin:0; - padding:0; - /*background-color:blue; - /* - background-image:url('background.png'); - background-repeat:no-repeat; - */ - background-size:100%; -} - -/* Tell the browser to render HTML 5 elements as block */ -header, footer, aside { - display: block; -} - -#intro { - margin: 20px; -} - -#content { - display: table; - width: 100%; -} - -#mainContent { - display: table-cell; - width: 620px; - padding-right: 22px; - padding-left: 22px; -} - -aside { - display: table-cell; - width: 300px; -} - -#nd_manual_configuration_dialog, #nd_show_log_dialog { - display:none; -} - -#ajaxBusy { - margin-left: auto; - margin-right: auto; -} - - .ui-button-text { - font-size: 10px; -} - -textarea { - width: 400px; - height: 200px; - /*resize: none;*/ -} - -h1 { - margin-top: 20px; -} - -h1, p{ - color:#333; - text-align:center; -} - diff --git a/src/html/networkdiscovery.html b/src/html/networkdiscovery.html deleted file mode 100644 index a1e62ac..0000000 --- a/src/html/networkdiscovery.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - -
      -

      Network Discovery

      -
      -
      -

      Welcome to the Network Discovery.
      -Please press F5 if you want to choose which interface to use.
      -We are now looking for usable interfaces and will go on as soon as we found one. This may take a few seconds.

      -
      -
      -
      - -
      -
      -
      - -

      -
      - -
      -
      
      -            
      - -
      -

      -

      - -
      -

      -
      - -
      -

      -

      All form fields are required.

      -
      -
      - - - - - - - - - - - - -
      -
      -
      - -
      -
      -
      -
      - -
      -
      -
      -

      RZ Uni Freiburg, 2011

      -
      - - diff --git a/src/html/networkdiscovery_debug.html b/src/html/networkdiscovery_debug.html deleted file mode 100644 index 06c1fe7..0000000 --- a/src/html/networkdiscovery_debug.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - -
      -

      Network Discovery

      -
      -
      -

      Welcome to the Network Discovery.
      -Please press F5 if you want to choose which interface to use.
      -We are now looking for usable interfaces and will go on as soon as we found one. This may take a few seconds.

      -
      -
      -
      - -
      -
      -
      - -

      -
      - -
      -
      
      -            
      - -
      -

      -

      - -
      -

      -
      - -
      -

      -

      All form fields are required.

      -
      -
      - - - - - - - - - - - - -
      -
      -
      - -
      -
      -
      -
      - -
      -
      -
      -

      RZ Uni Freiburg, 2011

      -
      - - diff --git a/src/html/networkdiscovery_userchoice.html b/src/html/networkdiscovery_userchoice.html deleted file mode 100644 index 3625fe0..0000000 --- a/src/html/networkdiscovery_userchoice.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - -
      -

      Network Discovery

      -
      -
      -

      Please press F5 if you want to choose which interface to use.

      -

      -
      -
      -

      RZ Uni Freiburg, 2011

      -
      - - diff --git a/src/html/networkdiscovery_userchoice_debug.html b/src/html/networkdiscovery_userchoice_debug.html deleted file mode 100644 index 88da8b4..0000000 --- a/src/html/networkdiscovery_userchoice_debug.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - -
      -

      Network Discovery

      -
      -
      -

      Please press F5 if you want to choose which interface to use.

      -

      -
      -
      -

      RZ Uni Freiburg, 2011

      -
      - - diff --git a/src/html/old.png b/src/html/old.png deleted file mode 100644 index 84dd7b3..0000000 Binary files a/src/html/old.png and /dev/null differ diff --git a/src/html/preload-debug.html b/src/html/preload-debug.html deleted file mode 100644 index 29d7391..0000000 --- a/src/html/preload-debug.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - -
      -
      -
      -

      Preboot GUI

      -

      Waiting on internet... - - -

      -
      -
      - -
      - - - diff --git a/src/html/preload.css b/src/html/preload.css deleted file mode 100644 index e1eff68..0000000 --- a/src/html/preload.css +++ /dev/null @@ -1,105 +0,0 @@ -html,body{ - height:100%; -} -body{ - margin:0; - padding:0; - background-color:black; - /* - background-image:url('background.png'); - background-repeat:no-repeat; - */ - background-size:100%; -} -#top{ - position:absolute; -} -#message{ - position:absolute; - top:37%; - width:100%; - font-size:90%; -} -h1, p{ - color:white; - text-align:center; -} -#container{ - min-height:100%; - margin-bottom:-50px; -} -* html #container{ - height:100%; -} -#footer-spacer{ - height:0px; -} -#footer{ - height:30px; -} -/* animation */ -/* position the bars and balls correctly (rotate them and translate them outward)*/ -.bar1 { - -moz-transform:rotate(0deg) translate(0, -40px); - -webkit-transform:rotate(0deg) translate(0, -40px);opacity:0.12; -} -.bar2 { - -moz-transform:rotate(45deg) translate(0, -40px); - -webkit-transform:rotate(45deg) translate(0, -40px);opacity:0.25; -} -.bar3 { - -moz-transform:rotate(90deg) translate(0, -40px); - -webkit-transform:rotate(90deg) translate(0, -40px);opacity:0.37; -} -.bar4 { - -moz-transform:rotate(135deg) translate(0, -40px); - -webkit-transform:rotate(135deg) translate(0, -40px);opacity:0.50; -} -.bar5 { - -moz-transform:rotate(180deg) translate(0, -40px); - -webkit-transform:rotate(180deg) translate(0, -40px);opacity:0.62; -} -.bar6 { - -moz-transform:rotate(225deg) translate(0, -40px); - -webkit-transform:rotate(225deg) translate(0, -40px);opacity:0.75; -} -.bar7 { - -moz-transform:rotate(270deg) translate(0, -40px); - -webkit-transform:rotate(270deg) translate(0, -40px);opacity:0.87; -} -.bar8 { - -moz-transform:rotate(315deg) translate(0, -40px); - -webkit-transform:rotate(315deg) translate(0, -40px);opacity:1; -} -#div4 { - position:absolute; - left:50%; - top:50%; - margin-left:-50px; - margin-top:-50px; - width:100px; - height:100px; - -moz-border-radius:100px; - -webkit-border-radius:100px; - -moz-transform:scale(0.5); - -webkit-transform:scale(0.5); - -webkit-animation-name: rotateThis; - -webkit-animation-duration:2s; - -webkit-animation-iteration-count:infinite; - -webkit-animation-timing-function:linear; -} -#div4 div { - width:20px; - height:20px; - background:#fff; - -moz-border-radius:40px; - -webkit-border-radius:40px; - position:absolute; - left:40px; - top:40px; -} -/* add a shadow to the first */ -#div4 div { - -moz-box-shadow:black 0 0 4px; - -webkit-box-shadow:black 0 0 4px; -} diff --git a/src/html/preload.html b/src/html/preload.html deleted file mode 100644 index bc0abd9..0000000 --- a/src/html/preload.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - -
      -
      -
      -

      Waiting for internet...

      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - - - diff --git a/src/interfaceconfiguration.cpp b/src/interfaceconfiguration.cpp deleted file mode 100644 index 3d09e52..0000000 --- a/src/interfaceconfiguration.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @class interfaceconfiguration - * - * @brief reads and stores a interface configuration. - * - * reads and stores a interface configuration. - * the config file has already to exist. It is created by the cdhcpcd client process. - * - */ - - - -#include "interfaceconfiguration.h" - -interfaceconfiguration::interfaceconfiguration() { - _tag = "[nd:InterfaceConfiguration]"; -} - -interfaceconfiguration::~interfaceconfiguration() { - // TODO Auto-generated destructor stub -} - -/** - * This method reads the configuration values out of a file. - * - * This method reads the configuration values out of a file. - * The file has to be created before by the customdhcpcd QProcess. - * (Overwrites the old values if they are already present.) - * - * @param pathToConfig - * contains the path to the configuration file. - */ -bool interfaceconfiguration::readConfigOutOfFile(QString pathToConfig) { - QFile file(pathToConfig); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << _tag << "couldn't open file:" << pathToConfig; - return false; - } - qDebug() << _tag << "read config file"; - while (!file.atEnd()) { - QString line(file.readLine()); - QStringList splitedLine = line.split("="); - QString name = splitedLine.first().trimmed(); - splitedLine.removeFirst(); - QString values = splitedLine.first().trimmed(); - values.remove(QChar('\'')); - - if (name.compare("IPADDR") == 0) { - this->ipAddress = values; - } else if (name.compare("NETMASK") == 0) { - this->netmask = values; - } else if (name.compare("NETWORK") == 0) { - this->network = values; - } else if (name.compare("BROADCAST") == 0) { - this->broadcast = values; - } else if (name.compare("ROUTES") == 0) { - this->routes = values; - } else if (name.compare("GATEWAYS") == 0) { - this->gateways = values; - this->gateway = this->gateways.split(" ").first().trimmed(); - } else if (name.compare("HOSTNAME") == 0) { - this->hostname = values; - } else if (name.compare("DNSSEARCH") == 0) { - this->dnssearch = values; - } else if (name.compare("DNSSERVERS") == 0) { - this->dnsservers = values; - } else if (name.compare("DHCPSID") == 0) { - this->dhcpsid = values; - } else if (name.compare("INTERFACE") == 0) { - this->interface = values; - } else if (name.compare("CLIENTID") == 0) { - this->clientid = values; - } else if (name.compare("DHCPCHADDR") == 0) { - this->dhcpchaddr = values; - } else { - qDebug() << _tag << "read unknown name" << name << values; - } - } - } else { - qDebug() << _tag << "file doesn't exist:" << pathToConfig; - return false; - } - return true; -} - -QString interfaceconfiguration::getBroadcast() { - return broadcast; -} - -QString interfaceconfiguration::getClientid() { - return clientid; -} - -QString interfaceconfiguration::getDhcpchaddr() { - return dhcpchaddr; -} - -QString interfaceconfiguration::getDhcpsid() { - return dhcpsid; -} -QString interfaceconfiguration::getDnssearch() { - return dnssearch; -} - -QString interfaceconfiguration::getDnsservers() { - return dnsservers; -} - -QString interfaceconfiguration::getGateways() { - return gateways; -} - -QString interfaceconfiguration::getGateway() { - return gateway; -} - -QString interfaceconfiguration::getHostname() { - return hostname; -} - -QString interfaceconfiguration::getInterface() { - return interface; -} - -QString interfaceconfiguration::getIpAddress() { - return ipAddress; -} - -QString interfaceconfiguration::getNetmask() { - return netmask; -} - -QString interfaceconfiguration::getNetwork() { - return network; -} - -QString interfaceconfiguration::getRoutes() { - return routes; -} diff --git a/src/interfaceconfiguration.h b/src/interfaceconfiguration.h deleted file mode 100644 index 475f689..0000000 --- a/src/interfaceconfiguration.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - */ - - - -#ifndef INTERFACECONFIGURATION_H_ -#define INTERFACECONFIGURATION_H_ - -#include - -class interfaceconfiguration: public QObject { -Q_OBJECT - -public: - interfaceconfiguration(); - interfaceconfiguration(const interfaceconfiguration &other); - - interfaceconfiguration &operator=(const interfaceconfiguration &other); - virtual ~interfaceconfiguration(); - - bool readConfigOutOfFile(QString pathToConfig); - QString getBroadcast(); - QString getClientid(); - QString getDhcpchaddr(); - QString getDhcpsid(); - QString getDnssearch(); - QString getDnsservers(); - QString getGateways(); - QString getGateway(); - QString getHostname(); - QString getInterface(); - QString getIpAddress(); - QString getNetmask(); - QString getNetwork(); - QString getRoutes(); - -private: - QString _tag; - - QString ipAddress; - QString netmask; - QString network; - QString broadcast; - QString routes; - QString gateway; - QString gateways; - QString hostname; - QString dnssearch; - QString dnsservers; - QString dhcpsid; - QString interface; - QString clientid; - QString dhcpchaddr; -}; - -#endif /* INTERFACECONFIGURATION_H_ */ diff --git a/src/javascriptinterface.cpp b/src/javascriptinterface.cpp deleted file mode 100644 index b45a2f9..0000000 --- a/src/javascriptinterface.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "fbgui.h" -#include "javascriptinterface.h" -#include "sysinfo.h" - -//------------------------------------------------------------------------------------------------------- -// Initialisation -//------------------------------------------------------------------------------------------------------- -/** - * A constructor. - * - * @param parent - * Is of type QWebFrame. - */ -JavascriptInterface::JavascriptInterface(QWebFrame *parent) { - qxtLog->debug() << "Initializing javascript interface..."; - _parent = parent; -} -//------------------------------------------------------------------------------------------------------- -/** - * An empty destructor. - */ -JavascriptInterface::~JavascriptInterface() { /* destructor dummy */ -} -//------------------------------------------------------------------------------------------------------- -/** - * Attaches an instance of this class to the DOM of the HTML page. - * - * Attaches an instance of this class to the DOM of the HTML page. - * This enables the possibility to call slots/methods of this class in - * JavaScript functions of HTML page. It also calls the - * JavascriptInterface::loadJQuery() method. - * - * @see JavascriptInterface::loadJQuery() - */ -void JavascriptInterface::attachToDOM() { - _parent->addToJavaScriptWindowObject(QString("fbgui"), this); - loadJQuery(); -} -//------------------------------------------------------------------------------------------------------- -/** - * This method load the required jQuery libraries into the HTML page. - * - * This method load the required jQuery libraries into the HTML page. - * The libraries are contained in the fbgui.qrc file. - * The Path to the files is: ":/html/js". - * Each library will be read and loaded into the HTML page via - * the evaluateJavaScript() method. - * - * @see JavascriptInterface::attachToDOM() - */ -void JavascriptInterface::loadJQuery() { - // to test if this actually works... - QString js; - QString pathToJsDir(DEFAULT_QRC_HTML_DIR); - pathToJsDir.append("/js"); - - QDir qrcJSDir(pathToJsDir); - QFileInfoList fiList = qrcJSDir.entryInfoList(); - QFileInfo fi; -foreach(fi, fiList) -{ - if (fi.suffix() == "js") { - //qDebug()<< fi.fileName(); - //qxtLog->debug() << fi.fileName(); - if (fi.fileName() != "test.js") { - QFile file; - file.setFileName(pathToJsDir + "/" + fi.fileName()); - file.open(QIODevice::ReadOnly); - js = file.readAll(); - file.close(); - - _parent->evaluateJavaScript(js); - //qxtLog->debug() << "evaluated " + fi.fileName(); - } - } -} -} -//------------------------------------------------------------------------------------------------------- -// Javascript functions for webpage -//------------------------------------------------------------------------------------------------------- -/** - * This method start a download. - * - * This method start a download. - * Can be called from inside a JavaScript function of the HTML page. - * Emits the JavascriptInterface::requestFile(const QString) signal. - */ -void JavascriptInterface::startDownload(const QString& filename) { - // ignore if empty filename - if (filename.isEmpty()) { - _parent->evaluateJavaScript("alert(\"No filename!\")"); - return; - } - emit requestFile(filename); -} -//------------------------------------------------------------------------------------------------------- -/** - * This method start a download. - * - * This method start a download. - * Can be called from inside a JavaScript function of the HTML page. - * - * @todo add some more informations - */ -void JavascriptInterface::setCallbackOnFinished(const QString& function) { - qxtLog->debug() << "[jsi] Callback set: " << function; - _callbackOnDownloadsFinished = QString(function); -} -//------------------------------------------------------------------------------------------------------- -/** - * This method delivers system informations. - * - * This method delivers system informations. Type of informations, are defined by - * the parameter. The output of this method depends on the parameter. - * Can be called from inside a JavaScript function of the HTML page. - * - * @param infoName - * Is of type QString. Defines which method will be called. Possible values are: - * - mac - * - ip - * - mbserial - * - usb - * - * @return QString - * the output of the called method or "info_error" if an error occurred - * (e. g. invalid parameter). - * - * @see SysInfo::getInfo(const QString& infoName) - */ -const QString JavascriptInterface::getSysInfo(const QString& info) { - SysInfo si; - return si.getInfo(info); -} -//------------------------------------------------------------------------------------------------------- -/** - * This method quits the whole program. - * - * This method quits the whole program. - * Can be called from inside a JavaScript function of the HTML page. - * Emits JavascriptInterface::quitFbgui() signal - */ -void JavascriptInterface::quit() { - emit quitFbgui(); -} - -//------------------------------------------------------------------------------------------------------- -/** - * This method performs a shutdown of the client. - * - * This method performs a shutdown of the client. - * Emits the JavascriptInterface::shutDownClient() signal.It is - * connected with the fbgui::performShutDown() method. - * - * @see fbgui::performShutDown() - */ -void JavascriptInterface::shutDown() { - emit shutDownClient(); -} -//------------------------------------------------------------------------------------------------------- -/** - * This method performs a reboot of the client. - * - * This method performs a reboot of the client. - * Emits the JavascriptInterface::rebootClient() signal. It is - * connected with the fbgui::performReboot() method. - * - * @see fbgui::performReboot() - */ -void JavascriptInterface::reboot() { - emit rebootClient(); -} -//------------------------------------------------------------------------------------------------------- -// Download Manager information exchange -//------------------------------------------------------------------------------------------------------- -/** - * This method delivers some informations about the downloading file. - * - * This method delivers some informations about the downloading file. - * - * @todo add some more informations - */ -void JavascriptInterface::downloadInfo(const QString& filename, - const double& filesize) { - QString code = QString("downloadInfo('\%1', \%2)").arg(filename).arg( - filesize); - _parent->evaluateJavaScript(code); -} -//------------------------------------------------------------------------------------------------------- -/** - * This method updates the progress bar. - * - * This method calls a Javascript function to update the progress bar of the download. - * Javascript must have a function called "updateProgress" to receive this information. - * - * @todo add some more informations - */ -void JavascriptInterface::updateProgressBar(const int& percent, - const double& speed, const QString& unit) { - if (percent == 0) - return; - QString code = QString("updateProgress(\%1, \%2, '\%3')").arg(percent).arg( - speed).arg(unit); - _parent->evaluateJavaScript(code); -} -//------------------------------------------------------------------------------------------------------- -/** - * This method sends out messages to Javascript. A corresponding function must be implemented - * on the webpage to receive these. - */ -void JavascriptInterface::notify(const QString& msg) { - qxtLog->debug() << "[jsi] Notifying: " << msg; - QString code = QString("notify('\%1')").arg(msg); - _parent->evaluateJavaScript(code); -} -//------------------------------------------------------------------------------------------------------- -/** - * Sets a callback function for when downloads are finished (will be called when the queue is empty). - */ -void JavascriptInterface::callbackOnFinished() { - QString code = QString("\%1").arg(_callbackOnDownloadsFinished); - _parent->evaluateJavaScript(code); -} -//------------------------------------------------------------------------------------------------------- -/** - * This method triggers the URL load *FOR DEBUGGING/TESTING PURPOSES* - - */ -void JavascriptInterface::trigger() { - QFile file(fileToTriggerURL); - if (file.open(QIODevice::WriteOnly)) { - file.write("data\n"); - qxtLog->debug() << "[jsi] *trigger watcher*"; - } - file.close(); -} diff --git a/src/javascriptinterface.h b/src/javascriptinterface.h deleted file mode 100644 index cf2ec5b..0000000 --- a/src/javascriptinterface.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - * - * - * Interface for javascript. - * - */ - -#ifndef JAVASCRIPTINTERFACE_H_ -#define JAVASCRIPTINTERFACE_H_ - -#include "fbgui.h" - -class JavascriptInterface: public QObject { -Q_OBJECT -public: - JavascriptInterface(QWebFrame* parent); - ~JavascriptInterface(); - -private: - // pointer to parent - QWebFrame* _parent; - // function to be called withint javascript when downloads are done. - QString _callbackOnDownloadsFinished; - // loads jQuery code - void loadJQuery(); - - signals: - // request the file from download manager - void requestFile(const QString& filename); - // quit the application - void quitFbgui(); - // shut off the system. connected to fbgui::performShutDown() - void shutDownClient(); - // reboot the system. connected to fbgui::performReboot() - void rebootClient(); - -public slots: - // make sure the interface stays attached on webpage reload - void attachToDOM(); - - // slots for calling from the webpage - void startDownload(const QString& filename); - void setCallbackOnFinished(const QString& function); - const QString getSysInfo(const QString& info); - void quit(); - void shutDown(); - void reboot(); - - // callback when downloads are done. - void callbackOnFinished(); - - // slots for information exchange with the download manager. - void updateProgressBar(const int& percent, const double& speed, - const QString& unit); - void downloadInfo(const QString& filename, const double& filesize); - void notify(const QString& msg); - - // functions to help test functionality - void trigger(); -}; - -#endif // JAVASCRIPTINTERFACE_H_ diff --git a/src/loggerengine.cpp b/src/loggerengine.cpp deleted file mode 100644 index 8a0991d..0000000 --- a/src/loggerengine.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "loggerengine.h" - -// -------------------------------------------------------------------------------------------------- -// base of a custom logger engine for the framebuffer -//--------------------------------------------------------------------------------------------------- -LoggerEngine_fb::LoggerEngine_fb(QTextEdit *parent) : - QxtLoggerEngine() { - _debugConsole = parent; - //_initialized = false; - //setLogLevelsEnabled(QxtLogger::DebugLevel); - //enableLogging(); -} -LoggerEngine_fb::~LoggerEngine_fb() { -} - -void LoggerEngine_fb::initLoggerEngine() { - //_initialized = true; - return; -} - -void LoggerEngine_fb::killLoggerEngine() { - return; -} - -void LoggerEngine_fb::setLogLevelEnabled(QxtLogger::LogLevels, bool) { - //QxtLoggerEngine::setLogLevelsEnabled(level, enable); - //if (!enable) QxtLoggerEngine::setLogLevelsEnabled(QxtLogger::DebugLevel); -} -bool LoggerEngine_fb::isInitialized() const { - //return _initialized; - return true; -} - -void LoggerEngine_fb::writeFormatted(QxtLogger::LogLevel level, const QList & msgs) { - - // ignore in case no messages was passed. - if (msgs.isEmpty()) - return; - - // write timestamp header in format: [hh:mm:ss.zzz] - // example: [23:58:99.999] - QString header = '[' + QTime::currentTime().toString("hh:mm:ss.zzz") + "] "; - _debugConsole->insertPlainText(header); - - // only write to console for debug level - if (level == QxtLogger::DebugLevel) { - Q_FOREACH(const QVariant& out, msgs) - { - if (!out.isNull()) - _debugConsole->insertPlainText(out.toString()); - } - _debugConsole->insertPlainText(QString("\n")); - // autoscroll - QTextCursor c = _debugConsole->textCursor(); - c.movePosition(QTextCursor::End); - _debugConsole->setTextCursor(c); - } -} -//--------------------------------------------------------------------------------------------------- -// slighty modified QxtBasicSTDLoggerEngine -//--------------------------------------------------------------------------------------------------- -LoggerEngine_std::LoggerEngine_std() : - QxtBasicSTDLoggerEngine() { -} - -LoggerEngine_std::~LoggerEngine_std() { -} - -void LoggerEngine_std::writeToStdErr(const QString&, const QList &msgs) { - - if (msgs.isEmpty()) - return; - QString header = '[' + QTime::currentTime().toString("hh:mm:ss.zzz") + "] "; - QTextStream* errstream = stdErrStream(); - Q_ASSERT(errstream); - *errstream << header; - Q_FOREACH(const QVariant& out, msgs) - { - if (!out.isNull()) - *errstream << out.toString(); - } - *errstream << endl; -} -void LoggerEngine_std::writeToStdOut(const QString&, const QList &) { - // (level, msgs) - // reimplementing this is needed for compiling, - // we only need write to std::err, so this function is not needed -} -//--------------------------------------------------------------------------------------------------- -// slighty modified QxtBasicFileLoggerEngine -//--------------------------------------------------------------------------------------------------- -LoggerEngine_file::LoggerEngine_file(const QString& logFileName) : - QxtBasicFileLoggerEngine(logFileName) { - //setLogFileName(logFileName); -} - -LoggerEngine_file::~LoggerEngine_file() { -} - -void LoggerEngine_file::initLoggerEngine() { -} - -void LoggerEngine_file::writeToFile(const QString&, const QList &msgs) { - - if (msgs.isEmpty()) - return; - QIODevice* file = device(); - QString header = '[' + QTime::currentTime().toString("hh:mm:ss.zzz") + "] "; - file->write(header.toUtf8()); - Q_FOREACH(const QVariant& out, msgs) - { - if (!out.isNull()) - file->write(out.toString().toUtf8()); - } - file->write("\n"); -} diff --git a/src/loggerengine.h b/src/loggerengine.h deleted file mode 100644 index 1dfae4e..0000000 --- a/src/loggerengine.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - * - * - * Base for custom logger engines based on QxtLogger libs. - * - */ -#ifndef LOGGERENGINE_H_ -#define LOGGERENGINE_H_ - -#include -#include -#include - -//--------------------------------------------------------------------------------------------------- -// base of a custom logger engine for the framebuffer -//--------------------------------------------------------------------------------------------------- -class LoggerEngine_fb: public QxtLoggerEngine { -public: - LoggerEngine_fb(QTextEdit* parent); - ~LoggerEngine_fb(); - - // parent widget, target of messages - QTextEdit *_debugConsole; - bool _initialized; - - // reimplemented virtual functions of QxtLoggerEngine - void initLoggerEngine(); - void killLoggerEngine(); - void writeFormatted(QxtLogger::LogLevel level, const QList & messages); - void setLogLevelEnabled(QxtLogger::LogLevels level, bool enable = true); - bool isInitialized() const; - -}; -//--------------------------------------------------------------------------------------------------- -// slighty modified QxtBasicSTDLoggerEngine -//--------------------------------------------------------------------------------------------------- -class LoggerEngine_std: public QxtBasicSTDLoggerEngine { -public: - LoggerEngine_std(); - ~LoggerEngine_std(); - - // reimplemented virtual functions of QxtBasicSTDLoggerEngine - void writeToStdOut(const QString& level, const QList &msgs); - void writeToStdErr(const QString& str_level, const QList &msgs); -}; -//--------------------------------------------------------------------------------------------------- -// slighty modified QxtBasicFileLoggerEngine -//--------------------------------------------------------------------------------------------------- -class LoggerEngine_file: public QxtBasicFileLoggerEngine { -public: - LoggerEngine_file(const QString& logFileName); - ~LoggerEngine_file(); - void initLoggerEngine(); - - // reimplemented virtual functions of QxtBasicFileLoggerEngine - void writeToFile(const QString& level, const QList &msgs); -}; - -#endif // LOGGERENGINE_H_ diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index a187d01..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "loggerengine.h" -#include "fbgui.h" -#include "ndgui.h" - -#include "../common/fbgui.h" - -void printHelp() { - QTextStream qout(stdout); - qout << QObject::tr("Usage: ./fbgui [OPTIONS]") << endl; - qout << QObject::tr("Options:") << endl; - qout << "-c , --config= " << QObject::tr("Path to configuration file.") << endl; - qout << "-u , --url= " << QObject::tr("Sets the URL to be loaded.") << endl; - qout << "-d , --download= " << QObject::tr("Specify the download directory.") - << endl; - qout << "-t " << QObject::tr( - "Specify location of the file triggering the URL load.") << endl; - qout << "-s " << QObject::tr( - "Specify location of the file containing the serial number.") << endl; - qout << "-D , --debug= " << QObject::tr("Activate debug mode. [0,1]") << endl; - qout << "-h, --help " << QObject::tr("Prints this help.") << endl; - qout.flush(); - exit( EXIT_SUCCESS); -} - -int main(int argc, char *argv[]) { - // Initialisation of the QApplication: - // In QT, every application is composed of two separate - // components: the GUI-Client and the GUI-Server. - // - // The third parameter sets the application as the - // GUI-Server (aswell as the GUI-Client). - - QApplication app(argc, argv, QApplication::GuiServer); - app.setOrganizationName("team_projekt_2011"); - app.setApplicationName("prebootGUI"); - binPath = QApplication::applicationDirPath(); - - QTranslator translator; - translator.load(":" + QLocale::system().name()); - app.installTranslator(&translator); - - // parse command line arguments using getopt - QMap clOpts; - int longIndex = 0; - static const char *optString = "c:u:d:s:t:D:hl:"; - static const struct option longOpts[] = { { "config", required_argument, NULL, 'c' }, { "url", - required_argument, NULL, 'u' }, { "download", required_argument, NULL, 'd' }, { "serial", - required_argument, NULL, 's' }, { "trigger", required_argument, NULL, 't' }, { "debug", - required_argument, NULL, 'D' }, { "help", no_argument, NULL, 'h' }, { "log", - required_argument, NULL, 'l' }, - { "server", required_argument, NULL, 'S' }, - { "autoup", no_argument, NULL, 'a' }, - { "socketserverpath", required_argument, NULL, 'p' }, - { "pathtoexe", required_argument, NULL, 'e' } - }; - int opt = getopt_long(argc, argv, optString, longOpts, &longIndex); - while (opt != -1) { - switch (opt) { - case 'c': - clOpts.insert("configFile", optarg); - break; - case 'l': - clOpts.insert("logFile", optarg); - break; - case 'u': - clOpts.insert("url", optarg); - break; - case 'd': - clOpts.insert("downloadDir", optarg); - break; - case 's': - clOpts.insert("serialLocation", optarg); - break; - case 't': - clOpts.insert("trigger", optarg); - break; - case 'D': - clOpts.insert("debug", optarg); - break; - case 'h': - clOpts.insert("help", "help"); - break; - case 'S': - clOpts.insert("server", optarg); - break; - case 'a': - clOpts.insert("autoup", "autoup"); - break; - case 'p': - clOpts.insert("socketserverpath", optarg); - break; - case 'e': - clOpts.insert("pathtoexe", optarg); - break; - } - opt = getopt_long(argc, argv, optString, longOpts, &longIndex); - } - - if (clOpts.contains("help")) - printHelp(); - - if (clOpts.contains("debug")) { - debugMode = clOpts.value("debug").toInt(); - // start basic debug output on terminal - qxtLog->disableLoggerEngine("DEFAULT"); - qxtLog->enableLogLevels(QxtLogger::DebugLevel); - qxtLog->addLoggerEngine("std_logger", new LoggerEngine_std); - qxtLog->initLoggerEngine("std_logger"); - qxtLog->setMinimumLevel("std_logger", QxtLogger::DebugLevel); - } else - debugMode = -1; - - // look for config file either in: - // - the path found in the configuration file - // - the user's home directory (as .fbgui.conf) - // - /etc/fbgui.conf - - QString configFilePath; - QFileInfo confInfo; - if (clOpts.contains("configFile")) - configFilePath = clOpts.value("configFile"); - else { - confInfo = QFileInfo(QDir::home(), ".fbgui.conf"); - if (confInfo.exists()) - configFilePath = confInfo.absoluteFilePath(); - else { - confInfo = QFileInfo(QString("/etc/fbgui.conf")); - if (confInfo.exists()) - configFilePath = QString("/etc/fbgui.conf"); - else - configFilePath = DEFAULT_CONFIG_PATH; - } - } - - // read the config file - QSettings confFileSettings(configFilePath, QSettings::IniFormat); - confFileSettings.setIniCodec("UTF-8"); - - // set base URL to be loaded - if (clOpts.contains("url")) - baseURL = QUrl(clOpts.value("url")); - else if (confFileSettings.contains("default/pbs_url")) - baseURL = confFileSettings.value("default/pbs_url").toUrl(); - else - baseURL = DEFAULT_URL; - - // set directory for downloads - if (clOpts.contains("downloadDir")) - downloadPath = clOpts.value("downloadDir"); - else if (confFileSettings.contains("default/download_directory")) - downloadPath = confFileSettings.value("default/download_directory").toString(); - else - downloadPath = DEFAULT_DOWNLOAD_DIR; - - // set update interval for download progress functions of download manager. - if (confFileSettings.contains("default/update_interval")) - updateInterval = confFileSettings.value("default/update_interval").toInt(); - else - updateInterval = DEFAULT_UPDATE_INTERVAL; - - // set which file to watch to trigger loading of URL - if (clOpts.contains("trigger")) - fileToTriggerURL = clOpts.value("trigger"); - else if (confFileSettings.contains("default/file_trigger")) - fileToTriggerURL = confFileSettings.value("default/file_trigger").toString(); - else - fileToTriggerURL = DEFAULT_FILE_TRIGGER; - - // set serial location - if (clOpts.contains("serialLocation")) - serialLocation = clOpts.value("serialLocation"); - else if (confFileSettings.contains("default/serial_location")) - serialLocation = confFileSettings.value("default/serial_location").toString(); - else - serialLocation = QString("/serial"); // tests - - // save ip config location (file generated by uchpc) - if (confFileSettings.contains("default/ip_config")) - ipConfigFilePath = confFileSettings.value("default/ip_config").toString(); - - // save path to log file - if (clOpts.contains("logFile")) - logFilePath = clOpts.value("logFile"); - else if (confFileSettings.contains("default/log_file")) - logFilePath = confFileSettings.value("default/log_file").toString(); - else - logFilePath = DEFAULT_LOG_FILE_PATH; - - // - if (clOpts.contains("server")) - gServerIp = clOpts.value("server"); - else if (confFileSettings.contains("default/server")) - gServerIp = confFileSettings.value("default/server").toString(); - else - gServerIp = "209.85.148.105"; //that is a google server. change this to a proper default address - - // - if (clOpts.contains("autoup")) - gAutoUp = true; - else if (confFileSettings.contains("default/autoup")) - gAutoUp = confFileSettings.value("default/autoup").toBool(); - else - gAutoUp = false; - - // - if (clOpts.contains("socketserverpath")) - gSocketServerPath = clOpts.value("socketserverpath"); - else if (confFileSettings.contains("default/socketserverpath")) - gSocketServerPath = confFileSettings.value("default/socketserverpath").toString(); - else - gSocketServerPath = DEFAULT_QTSOCKETADDRESS; - - // - if (clOpts.contains("pathtoexe")) - gPathToDhcpExe = clOpts.value("pathtoexe"); - else if (confFileSettings.contains("default/pathtoexe")) - gPathToDhcpExe = confFileSettings.value("default/pathtoexe").toString(); - else - gPathToDhcpExe = DEFAULT_PATHTODHCPCDEXE; - - - - // write always a log file - // // activate file logger if debug mode activated. - // if (debugMode > -1) { - // start debug logging to file. - qxtLog->addLoggerEngine("file_logger", new LoggerEngine_file(logFilePath)); - qxtLog->setMinimumLevel("file_logger", QxtLogger::DebugLevel); - // } - - // print config - qxtLog->debug() << "************* CONFIG INFO *************"; - qxtLog->debug() << "configFilePath: " << configFilePath.toUtf8(); - qxtLog->debug() << "logFilePath: " << logFilePath.toUtf8(); - qxtLog->debug() << "ipConfigFilePath: " << ipConfigFilePath.toUtf8(); - qxtLog->debug() << "baseURL: " << baseURL.toString().toUtf8(); - qxtLog->debug() << "downloadDir : " << downloadPath.toUtf8(); - qxtLog->debug() << "trigger: " << fileToTriggerURL.toUtf8(); - qxtLog->debug() << "serialLocation: " << serialLocation.toUtf8(); - qxtLog->debug() << "server: " << gServerIp.toUtf8(); - qxtLog->debug() << "autoup: " << gAutoUp; - qxtLog->debug() << "socketserverpath: " << gSocketServerPath.toUtf8(); - qxtLog->debug() << "pathtoexe: " << gPathToDhcpExe.toUtf8(); - qxtLog->debug() << "*******************************************"; - - // set invisible cursor - //QWSServer::instance()->setCursorVisible(false); - - // set default keyboard / mouse drivers. TODO: fix this, doesn't work... - //QWSServer::instance()->setDefaultKeyboard("TTY:/dev/tty0"); - //QWSServer::instance()->setDefaultMouse("IntelliMouse:/dev/mice"); - - - // start ndgui - qxtLog->debug() << "Initializing ndgui..."; - ndgui ngui; - fbgui gui; - - QObject::connect(&ngui, SIGNAL(initFbgui()), &gui, SLOT(init())); - ngui.show(); - return app.exec(); -} diff --git a/src/ndgui.cpp b/src/ndgui.cpp deleted file mode 100644 index 3034051..0000000 --- a/src/ndgui.cpp +++ /dev/null @@ -1,588 +0,0 @@ -/** - * @class ndgui - * - * @brief the GUI. - * - * This class is responsible for creating and displaying the user interface. - * It also connects the webView via QWebBridge to javascript functions inside the html files. - */ - - - -#include "ndgui.h" - -QString gServerIp(""); -bool gAutoUp = true; -QString gSocketServerPath(""); -QString gPathToDhcpExe(""); - - - -/** - * constructor - */ -ndgui::ndgui(QMainWindow *parent) : - QMainWindow(parent) { - init(); -} - - - -/** - * destructor - */ -ndgui::~ndgui() { - delete _debugConsole; - delete _toggleDebugConsole; - delete _allowUserChoice; - delete _tryAgain; - delete _webView; - delete _networkDiscovery; -} - - - -/** - * @brief initialize all variables and prepare everything for a successful run - */ -void ndgui::init() { - _tag = "[nd:ndgui]"; - - _started = false; - _userChoice = false; - _ifNameList.clear(); - _manConfList.clear(); - - setupLayout(); - createAction(); - - _networkDiscovery = new NetworkDiscovery(); - connect(_networkDiscovery, SIGNAL(addInterface(const QString &)), this, - SLOT(addInterface( const QString &))); - connect(_networkDiscovery, - SIGNAL(changeProgressBarValue(const QString & , const int& )), - this, SLOT(updateIfProgressBar(const QString & , const int&))); - connect(_networkDiscovery, SIGNAL(connectionEstablished(QString)), this, - SLOT(handleConnectionEstablished(QString))); - connect(_networkDiscovery, SIGNAL(abortBoot(QString)), this, - SLOT(abortBoot(const QString))); - connect(_networkDiscovery, SIGNAL(updateIfStatus(QString,QString)), this, - SLOT(updateIfStatus(const QString &, const QString &))); - connect(_networkDiscovery, SIGNAL(updateStatus(QString)), this, - SLOT(updateStatus(const QString&))); - connect(_networkDiscovery, SIGNAL(allProcessesFinished()), this, - SLOT(handleAllProcessesFinished())); - connect(_networkDiscovery, SIGNAL(continueBoot(QString)), this, - SLOT(continueBoot(QString))); - connect(_networkDiscovery, SIGNAL(continueBootWithoutCheck(QString )), - this, SLOT(continueBootWithoutCheck(QString))); - - connect(_webView->page()->mainFrame(), SIGNAL( - javaScriptWindowObjectCleared()), this, SLOT(attachToDOM())); - connect(_webView, SIGNAL(loadFinished(bool)), this, SLOT(startSingleShot())); - - setWindowTitle(tr("NetD")); - setAttribute(Qt::WA_QuitOnClose, true); - setWindowFlags(Qt::FramelessWindowHint); - showFullScreen(); - - if (debugMode > -1) { - _webView->load(QUrl("qrc:html/networkdiscovery_debug.html")); - } else { - _webView->load(QUrl("qrc:html/networkdiscovery.html")); - - } - - _webView->show(); -} - - - -/** - * @brief This method sets the used Layout. - * - * This method sets the used Layout. Possible layout are: - * - browser mode: only the browser is visible - * - debug mode: the screen is divided into the browser and a debug - * out console - */ -void ndgui::setupLayout() { - // setup layout of the gui: debug split or browser - _webView = new QWebView(this); - _webView->setContextMenuPolicy(Qt::NoContextMenu); // if this does not work try Qt::CustomContextMenu - - if (debugMode == 1) { - // split main window in browser & debug console - createDebugConsole(); - _splitter = new QSplitter(Qt::Vertical, this); - _splitter->addWidget(_webView); - _splitter->addWidget(_debugConsole); - setCentralWidget(_splitter); - } else { - _webView->page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); - setCentralWidget(_webView); - } -} - - - -/** - * @brief This method creates a debug console as a widget. - * - * It is basicly a QTextEdit widget as provided by QT's Framework. - * An action to toggle this widget is implemented (CTRL + D). - * - * @see fbgui::toggleDebugConsole() - */ -void ndgui::createDebugConsole() { - // create the debug console widget - _debugConsole = new QTextEdit(this); - _debugConsole->setWindowFlags(Qt::FramelessWindowHint); - // fanciness - QPalette pal; - pal.setColor(QPalette::Base, Qt::black); - _debugConsole->setPalette(pal); - _debugConsole->setTextColor(Qt::white); - // enable custom logger engine - qxtLog->addLoggerEngine("fb_logger", new LoggerEngine_fb(_debugConsole)); - //qxtLog->initLoggerEngine("fb_logger"); - qxtLog->setMinimumLevel("fb_logger", QxtLogger::DebugLevel); - // CTRL + D toggles debug window - _toggleDebugConsole = new QAction(tr("&toggleDebug"), this); - _toggleDebugConsole->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); - addAction(_toggleDebugConsole); - connect(_toggleDebugConsole, SIGNAL(triggered()), this, SLOT( - toggleDebugConsole())); -} - - - -/** - * @brief This method toggles the debug console. - * - * Toggle the visibility of the debug console if the action _toggleDebugConsole is triggered. - * - * @see fbgui::createDebugConsole() - */ -void ndgui::toggleDebugConsole() { - (_debugConsole->isVisible()) ? _debugConsole->hide() : _debugConsole->show(); -} - - - -/** - * @brief Create actions - * - * creates an action which you can trigger with the F5 and F9 Button. - */ -void ndgui::createAction() { - _allowUserChoice = new QAction(tr("&userChoice"), this); - _allowUserChoice->setShortcut(QKeySequence(Qt::Key_F5)); - connect(_allowUserChoice, SIGNAL(triggered()), this, SLOT(setUserChoiceTrue())); - this->addAction(_allowUserChoice); - _tryAgain = new QAction(tr("&tryAgain"), this); - _tryAgain->setShortcut(QKeySequence(Qt::Key_F9)); - connect(_tryAgain, SIGNAL(triggered()), this, SLOT(tryAgain())); - this->addAction(_tryAgain); -} - - - -/** - * @brief set userChoice true - * - * is the connected to the triggered action pressing the F5 button. - * set the _userChoice member true - */ -void ndgui::setUserChoiceTrue() { - _userChoice = true; -} - - - -/** - * @brief starts a singleshot event. - * - * is connected to the singleShot event. Triggering this method means - * that we go on with the main NetworkDiscovery screen. - * connects the loadFinished signal of the _webView with the - * startNetworkDiscovery slot and removes the - * action. - */ -void ndgui::startSingleShot() { - - qxtLog->debug() << _tag << "start singel shot"; - QTimer::singleShot(3000, this, SLOT(startNetworkDiscovery())); -} - - - -/** - * @brief start the network discovery - * - * main starting point of the whole procedure. - * disconnect the loadFinished signal with the startNetworkDiscovery - * and starts the networkDiscovery. - */ -void ndgui::startNetworkDiscovery() { - disconnect(_webView, SIGNAL(loadFinished(bool)), this, - SLOT(startSingleShot())); - if (!_started) { - _started = true; - _networkDiscovery->initAndRun(gServerIp, _userChoice, gAutoUp, - logFilePath, gSocketServerPath, gPathToDhcpExe); - } else { - qxtLog->debug() << _tag << "NetworkDiscovery already started"; - } -} - - - -/** - * @brief handle if a interface is able to connect - * - * if we have a user choice (_userChoice = true) than networkDiscovery will - * emit connectionEstablished signals. - * Add the interface name to a _ifNameList. This list holds all interfaces - * the user can choose out of. - */ -void ndgui::handleConnectionEstablished(QString ifName) { - _ifNameList.append(ifName); -} - - - -/** - * @brief determines if we continue the boot sequence or if we show the chooseInterface or abortBoot dialog - * - * if we have a user choice (_userChoice = true) than networkDiscovery will - * emit a allProcessesFinished signal if all processes are done. - * This method determines if user will see an abort boot dialog (no interface names in - * the ifNameList list) or an - * choose interface dialog (one or more interface names in the list (add with - * handleConnectionEstablished)). - */ -void ndgui::handleAllProcessesFinished() { - qxtLog->debug() << _tag << "all Processes finished"; - _allowUserChoice->setEnabled(false); - if (_ifNameList.size() > 0) { - if (_userChoice) { - QString jsonArr = "["; - for (int i = 0; i < _ifNameList.size() - 1; i++) { - jsonArr += "\"" + _ifNameList.value(i) + "\","; - } - jsonArr += "\"" + _ifNameList.last() + "\"]"; - chooseInterfaceDialog(jsonArr); - } else { - foreach(QString i, _ifNameList) - { - if (_networkDiscovery->checkConnectivity(i)) { - continueBootWithoutCheck(i); - break; - } - } - } - } else { - qxtLog->debug() << _tag << " No usable interfaces found!: " - << _networkDiscovery->GetErrorStr(); - qxtLog->debug() << _tag << " list is empty"; - abortBoot("No usable interfaces found!" - + _networkDiscovery->GetErrorStr()); - } -} - - - -/** - * @brief restart the system - * - * this method will restart the system. - * triggered through a button click in the gui. - */ -void ndgui::restartSystem() { - QFile file("/proc/sysrq-trigger"); - if (file.open(QIODevice::WriteOnly)) { - file.write("b"); - file.close(); - } else { - qxtLog->debug() << _tag << "Could not open /proc/sysrq-trigger"; - } -} - - - -/** - * @brief shut down the system - * - * this method will restart the system. - * triggered through a button click in the gui. - */ -void ndgui::shutDownSystem() { - QFile file("/proc/sysrq-trigger"); - if (file.open(QIODevice::WriteOnly)) { - file.write("o"); - file.close(); - } else { - qxtLog->debug() << _tag << "Could not open /proc/sysrq-trigger"; - } -} - - - -/** - * @brief continue the boot sequence - * - * represents the end of the NetworkDiscovery life time. - * will start the fbgui screen. All networkDiscovery signals - * will be ignored after this point. - */ -//void ndgui::continueBoot(QString ifName, int userChoice) { -void ndgui::continueBoot(QString ifName) { - if (_networkDiscovery->checkConnectivity(ifName)) { - qxtLog->debug() << _tag << " continue with interface: " << ifName; - emit initFbgui(); - this->close(); - } else { - abortBoot( - "Interface was suddenly made unusable. Please check the log and try again."); - } - -} - - - -/** - * @brief continue the boot sequence without further checking if the connection is still possible. - */ -void ndgui::continueBootWithoutCheck(QString ifName) { - qxtLog->debug() << _tag << " continue with interface: " << ifName; - emit initFbgui(); - this->close(); -} - - - -/** - * @brief read the log file. Log File will be presented inside of a dialog. - */ -QString ndgui::readLogFile() { - qxtLog->debug() << _tag << "show log"; - return _networkDiscovery->readLogFile(); -} - - - -/** - * @brief starts the whole application again. - */ -void ndgui::tryAgain() { - qxtLog->debug()<< _tag << " try again "; - _networkDiscovery->prepareTryAgain(); - if(debugMode > -1) { - delete _splitter; - delete _debugConsole; - delete _toggleDebugConsole; - } - delete _allowUserChoice; - delete _tryAgain; - delete _webView; - delete _networkDiscovery; - - init(); - -} - - - -/*test html gui version*/ - -/** - * @brief fills the drop down box of the manual interface configuration - * dialog. - */ -QVariantList ndgui::getManualConfInterfaces() { - qxtLog->debug() << _tag << "call getManualConfInterfaces"; - QVariantList jsonArr; - foreach (QString s, _manConfList) { - QVariant e(s); - jsonArr << e; - } - qxtLog->debug() << _tag << "value of jsonArr:" << jsonArr; - return jsonArr; -} - - -/** - * @brief return a json formated interface configuration - * - * @param ifName - * the name of the interface - */ -QVariantMap ndgui::getInterfaceConf(QString ifName) { - - return _networkDiscovery->getInterfaceConfig(ifName); -} - - - -/** - * @brief takes the entered manual configuration dates and delivers it - * to the networkDiscovery for further actions. - * - * @param jsonArr - * a jsonArr which contains the manual entered interface configuration - */ -int ndgui::ip4_setManualConfiguration(QVariantMap jsonArr) { - return _networkDiscovery->ip4_setManualConfiguration(jsonArr); - -} - - - -/* slots */ -/************************************************/ -////////////////////////////////////////////////// -/************************************************/ - -/** - * @brief stellt ein ndgui/fbgui Objekt zur verwendung durch die html bereit. - */ -void ndgui::attachToDOM(){ - _webView->page()->mainFrame()->addToJavaScriptWindowObject(QString("fbgui"), this); - loadJQuery(); -} - - - -/** - * @brief load jQuery and js scripts into the page so that all javascript functions will work. - */ -void ndgui::loadJQuery() { - QString js; - QString pathToJsDir(":/html"); - pathToJsDir.append("/js"); - - QDir qrcJSDir(pathToJsDir); - QFileInfoList fiList = qrcJSDir.entryInfoList(); - QFileInfo fi; - foreach(fi, fiList) - { - if (fi.suffix() == "js") { - //qxtLog->debug()<< fi.fileName(); - //qxtLog->debug() << fi.fileName(); - //if (fi.fileName() != "test.js" && fi.fileName() != "nd-functions.js") { - QFile file; - file.setFileName(pathToJsDir + "/" + fi.fileName()); - file.open(QIODevice::ReadOnly); - js = file.readAll(); - file.close(); - - _webView->page()->mainFrame()->evaluateJavaScript(js); - //qxtLog->debug() << "evaluated " + fi.fileName(); - //} - } - } -} - - - - -/** - * @brief show abortBoot dialog - * - * @param msg - * the message, displayed in the dialog. - */ -void ndgui::abortBoot(const QString msg) { - QString code = QString("abortBootDialog('\%1')").arg(msg); - _webView->page()->mainFrame()->evaluateJavaScript(code); -} - - - -/** - * @brief opens ths chooseInterfaceDialog - * - * @param msg - * the interfaces as json formated string. will be displayed in a select box. - */ -void ndgui::chooseInterfaceDialog(const QString msg) { - QString code = QString("chooseInterfaceDialog(\%1)").arg(msg); - _webView->page()->mainFrame()->evaluateJavaScript(code); -} - - - -/** - * @brief updates the over all status - * - * @param status - * the new status message - */ -void ndgui::updateStatus(const QString &status) { - if (status == "") - return; - QString code = QString("updateStatus('\%1')").arg(status); - _webView->page()->mainFrame()->evaluateJavaScript(code); -} - - - -/** - * @brief updates the progress bar for each interface. - * - * @param ifname - * the name ot the interface to update - * - * @param percent - * the progress in percent - */ -void ndgui::updateIfProgressBar(const QString &ifName, const int& percent) { - if (percent == 0) - return; - QString code = QString("updateIfProgressBar('\%1',\%2)").arg(ifName).arg(percent); - _webView->page()->mainFrame()->evaluateJavaScript(code); -} - - - -/** - * @brief update the status for each interface - * - * @param ifName - * the name ot the interface to update - * - * @param status - * the new status of the interface. - */ -void ndgui::updateIfStatus(const QString &ifName, const QString &status) { - if (ifName == "") - return; - QString code = QString("updateIfStatus('\%1','\%2')").arg(ifName).arg(status); - _webView->page()->mainFrame()->evaluateJavaScript(code); -} - - - -/** - * @brief adds an interface to the DOM tree. Creates its progress bar and it's status label. - * - * @param ifName - * name of the new interface. - */ -void ndgui::addInterface(const QString &ifName) { - if (ifName == "") - return; - _manConfList.append(ifName); - QString code = QString("addInterface('\%1')").arg(ifName); - _webView->page()->mainFrame()->evaluateJavaScript(code); -} - - - -/** - * @brief just for debugging. - */ -void ndgui::notifyCall(QString msg){ - qxtLog->debug() << _tag << "------ called:" << msg; -} diff --git a/src/ndgui.h b/src/ndgui.h deleted file mode 100644 index 41a7bbf..0000000 --- a/src/ndgui.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - */ - - - -#ifndef NDGUI_H -#define NDGUI_H - -#include -#include -#include - -#include "fbgui.h" -#include "loggerengine.h" -#include "networkdiscovery.h" - - -extern QString gServerIp; -extern bool gAutoUp; -extern QString gSocketServerPath; -extern QString gPathToDhcpExe; - -class ndgui: public QMainWindow { -Q_OBJECT - -public: - ndgui(QMainWindow *parent = 0); - ~ndgui(); - Q_INVOKABLE QVariantList getManualConfInterfaces(); - Q_INVOKABLE int ip4_setManualConfiguration(QVariantMap result); - Q_INVOKABLE QString readLogFile(); - Q_INVOKABLE QVariantMap getInterfaceConf(QString ifName); - -public slots: - void handleConnectionEstablished(QString ifName); - void abortBoot(QString msg); - void chooseInterfaceDialog(QString msg); - void handleAllProcessesFinished(); - - void restartSystem(); - void shutDownSystem(); - void continueBoot(QString ifName); - void continueBootWithoutCheck(QString ifName); - void tryAgain(); - - - void startSingleShot(); - void startNetworkDiscovery(); - - /*test for html gui version*/ - void attachToDOM(); - void loadJQuery(); - void addInterface(const QString &ifName); - void updateIfStatus(const QString &ifName, const QString &status); - void updateStatus(const QString &status); - void updateIfProgressBar(const QString &ifName, const int& percent); - void notifyCall(QString msg); - - signals: - void initFbgui(); - -private slots: - void setUserChoiceTrue(); - -private: - - QString _tag; - - void createAction(); - - bool _userChoice; - - bool _started; - - QWebView* _webView; - - QAction* _allowUserChoice; - - QAction* _tryAgain; - - NetworkDiscovery* _networkDiscovery; - - QList _ifNameList; // maps interfaceName to its gateway - - QList _manConfList; - - QString _manualConfInterfaces; - - // QSplitter to split the main window in two resizable frames. - QSplitter* _splitter; - // QTextEdit implementing a minimalistic debug console. - QTextEdit* _debugConsole; - - // triggers toggleDebugConsole() - QAction* _toggleDebugConsole; - - void init(); - void setupLayout(); - void createDebugConsole(); - void toggleDebugConsole(); - - -}; - -#endif // NDGUI_H diff --git a/src/networkdiscovery.cpp b/src/networkdiscovery.cpp deleted file mode 100644 index 132429c..0000000 --- a/src/networkdiscovery.cpp +++ /dev/null @@ -1,990 +0,0 @@ -/** - * @class NetworkDiscovery - * - * @brief the logic behind the NetworkDiscovery. - * - * This class holds all the logic of the NetworkDiscovery. It's main task is to search for usable - * interfaces, check if they are wired (in Running state) and start a cdhcpcd process for each interface. - * It also sends signals to the ndgui class for presenting notifications to the user. - * - */ - - - -#include -#include - -#include "networkdiscovery.h" - - - - -/** - * constructor - */ -NetworkDiscovery::NetworkDiscovery(QObject *parent) { - _tag = "[nd:NetworkDiscovery]"; - _server = new QLocalServer(this); -} - - - -/** - * destructor - */ -NetworkDiscovery::~NetworkDiscovery() { - delete _networkManager; - delete _server; - foreach(QProcess* p, _clientProcessToIfNameMap.keys()) { - delete p; - } - foreach(interfaceconfiguration* i, _ifcMap.values()) { - delete i; - } -} - - - -/** - * initialize all important class members and start the main work. - * - * @param serverIp - * the ip of the server with which we are testing the connectivity. - * - * @param userChoice - * true if the user wishes to have a user choice. true: the chooseInterfaceDialog will be showed. - * - * @param autoUp - * true if we want to "auto Up" all down interfaces. - * - * @param pathToLogFile - * the path to the log file. - * - * @param serverPath - * the path to the server socket (default value: DEFAULT_QTSOCKETADDRESS "/var/tmp/qt_c_socket_default") - * - * @param pathToExe - * the path to the customdhcpcd exe. (default value: #define DEFAULT_QTSOCKETADDRESS "/var/tmp/qt_c_socket_default") - * - * @param args - * additional arguments for the customdhcpcd client. (default value: NULL) - */ -void NetworkDiscovery::initAndRun(QString serverIp, bool userChoice, bool autoUp, QString pathToLogFile, QString serverPath, QString pathToExe, - QStringList* args) { - - _serverIp = serverIp; - _userChoice = userChoice; - _autoUp = autoUp; - _pathToLogFile = pathToLogFile; - _serverPath = serverPath; - - _pathToDhcpcdExe = pathToExe; - _blocked = false; - _numberOfProcesses = 0; - _ifUpCountdown = 10; - - _errorStr = ""; - _networkManager = new NetworkManager(); - _clientProcessToIfNameMap.clear(); - _clients.clear(); - _dhcpcdArguments.clear(); - _ifDownList.clear(); - _ifNameToClient.clear(); - _ifUpList.clear(); - _ifcMap.clear(); - _server = new QLocalServer(); - - if (serverPath != DEFAULT_QTSOCKETADDRESS) { - _dhcpcdArguments.append("-q"); - _dhcpcdArguments.append(serverPath); - } - /* delete the file at serverPath. this is necessary since in case the application crashes, the file still - * exists which leads to an error. - */ - - if(QFile::exists(serverPath)) { - QFile::remove(serverPath); - } - - emit updateStatus("try to create server socket"); - if (!_server->listen(serverPath)) { - // emit signal to the gui that a critial error occoured - qxtLog->debug() << _tag << " Unable to start server: " - << _server->errorString(); - emit - abortBoot("Unable to start server: " + _server->errorString()); - return; - } - - killDHCPCD(); - - // check if the path to the customdhcpcd file is correct - emit updateStatus("check if cdhcpcd is available"); - QFileInfo fInfo(_pathToDhcpcdExe); - if (!fInfo.exists()) { - qxtLog->debug() << _tag - << " could not find customdhcpcd exe. Please check the path to this file."; - emit abortBoot( - "could not find customdhcpcd exe. Please check the path to this file."); - return; - } - - connect(_server, SIGNAL(newConnection()), this, SLOT(handleNewConnection())); - connect(this, SIGNAL(readyForRun()), this, SLOT(slotReadyForRun())); - - if (args != NULL && !args->isEmpty()) { - qxtLog->debug() << _tag << "added additional args"; - _dhcpcdArguments.append(*args); - } - emit updateStatus("start mainwork"); - mainWork(); -} - - - -/** - * @brief the main work. Here we start with searching for usable interfaces and check the IsRunning state. - * - * the main work. Here we start with searching for usable interfaces and check the IsRunning state. - * check every second the IsRunning state. Do this as long the counter (@see _ifUpCountdown) is greater than 0. - * Default: _ifUpCountdown = 10. - */ -void NetworkDiscovery::mainWork() -{ - if (_autoUp) { - emit updateStatus("search for usable interfaces (with auto Up)"); - getListOfNetworkInterfacesWithAutoUp(); - } else { - emit updateStatus("search for usable interfaces"); - getListOfNetworkInterfaces(); - } - emit updateStatus("check if interfaces are in running state"); - _timer = new QTimer(this); - connect(_timer, SIGNAL(timeout()), this, SLOT(checkForIsRunning())); - _timer->start(1000); -} - - - -/** - * searches for usable interfaces and puts them into a list. - * if the interface is down, put it in the _ifDownList, try to bring it up. - * else put it in the _ifUpList. - * usable interfaces are: can Broadcast, no loopback, no point to point, name is not in the BlackList, - */ -void NetworkDiscovery::getListOfNetworkInterfacesWithAutoUp() { - QList nIList = QNetworkInterface::allInterfaces(); - _ifUpList.clear(); - _ifDownList.clear(); - if (nIList.size() > 0) { - foreach(QNetworkInterface nI, nIList) - { - qxtLog->debug() << _tag << "found Interface:" << nI.humanReadableName(); - if ((nI.flags() & QNetworkInterface::CanBroadcast)) { - qxtLog->debug() << _tag << " flags: can broadcast "; - } - if ((nI.flags() & QNetworkInterface::IsLoopBack)) { - qxtLog->debug() << _tag << " flags: is LoopBack "; - } - if ((nI.flags() & QNetworkInterface::IsPointToPoint)) { - qxtLog->debug() << _tag << " flags: is Point to Point "; - } - if ((nI.flags() & QNetworkInterface::IsRunning)) { - qxtLog->debug() << _tag << " flags: is Running "; - } - if ((nI.flags() & QNetworkInterface::IsUp)) { - qxtLog->debug() << _tag << " flags: is Up "; - } - - if (((!(nI.flags() & QNetworkInterface::CanBroadcast) - || nI.flags() & QNetworkInterface::IsLoopBack) - || nI.flags() & QNetworkInterface::IsPointToPoint) - || checkBlackList(nI.humanReadableName())) { - continue; - } - if ((nI.flags() & QNetworkInterface::IsRunning)) { - _ifUpList.append(nI.humanReadableName()); - } - else if (!(nI.flags() & QNetworkInterface::IsUp)) { - _networkManager->bringInterfaceUP(nI.humanReadableName()); - qxtLog->debug() << _tag << " interface is down, try to bring up: " << nI.humanReadableName() ; - _ifDownList.append(nI.humanReadableName()); - } - else if (!(nI.flags() & QNetworkInterface::IsRunning)) { - _ifDownList.append(nI.humanReadableName()); - } - } - } else { - qxtLog->debug() << _tag << " no interfaces found! "; - } -} - - - -/** - * searches for usable interfaces which are up and running and put them into a list. - * usable interfaces are: can Broadcast, no loopback, no point to point, name is not in the BlackList, - */ -void NetworkDiscovery::getListOfNetworkInterfaces() { - QList nIList = QNetworkInterface::allInterfaces(); - _ifUpList.clear(); - _ifDownList.clear(); - if (nIList.size() > 0) { - foreach(QNetworkInterface nI, nIList) - { - qxtLog->debug() << _tag << "found Interface:" - << nI.humanReadableName(); - if ((nI.flags() & QNetworkInterface::CanBroadcast)) { - qxtLog->debug() << _tag << " flags: can broadcast "; - } - if ((nI.flags() & QNetworkInterface::IsLoopBack)) { - qxtLog->debug() << _tag << " flags: is LoopBack "; - } - if ((nI.flags() & QNetworkInterface::IsPointToPoint)) { - qxtLog->debug() << _tag << " flags: is Point to Point "; - } - if ((nI.flags() & QNetworkInterface::IsRunning)) { - qxtLog->debug() << _tag << " flags: is Running "; - } - if ((nI.flags() & QNetworkInterface::IsUp)) { - qxtLog->debug() << _tag << " flags: is Up "; - } - if (((!(nI.flags() & QNetworkInterface::CanBroadcast) - || nI.flags() & QNetworkInterface::IsLoopBack) - || nI.flags() & QNetworkInterface::IsPointToPoint) - || !(nI.flags() & QNetworkInterface::IsUp) - || checkBlackList(nI.humanReadableName())) { - continue; - } - if (!(nI.flags() & QNetworkInterface::IsRunning)) { - _ifDownList.append(nI.humanReadableName()); - } else { - _ifUpList.append(nI.humanReadableName()); - } - } - } else { - qxtLog->debug() << _tag << " no interfaces found! "; - } -} - - - -/** - * only called if autoUp == true. - * check the IsRunning flag of each interface in the _ifDownList. - * connected to the timeout signal of the timer. - */ -void NetworkDiscovery::checkForIsRunning() { - bool isRunning = false; - foreach(QString i, _ifDownList) { - QNetworkInterface networkInterface = QNetworkInterface::interfaceFromName(i); - isRunning = (networkInterface.flags() & QNetworkInterface::IsRunning); - if (isRunning) { - _ifUpList.append(i); - _ifDownList.removeAt(_ifDownList.indexOf(i)); - } - } - _ifUpCountdown--; - if ((_ifUpCountdown <= 0 ) || _ifDownList.isEmpty()) { - // shut down timer - _timer->stop(); - delete _timer; - emit readyForRun(); - } -} - - - -/** - * emits the addInterface signal for each interface name in _ifUpList - * and calls the runDHCPCD method. - * if the _ifUpList is empty, this method emits an abortBoot signal. - * connected to the readyForRun signal. - */ -void NetworkDiscovery::slotReadyForRun() { - if (_ifUpList.size() > 0) { - foreach(QString i, _ifUpList) { - qxtLog->debug() << _tag << " emit addInterface : " << i; - emit addInterface(i); - } - _numberOfProcesses = _ifUpList.size(); - emit updateStatus("start dhcp client for each interface"); - runDHCPCD( _ifUpList); - } else { - qxtLog->debug() << _tag << " list is empty. Have not found usable interface. "; - emit - foreach(QString i, _ifDownList) { - qxtLog->debug() << _tag << " " << i << " is not in running state. (check cable)"; - } - abortBoot("All interfaces are not usable. (e.g. please check if all network cables are plugged in. Read the log for more informations.)"); - return; - } -} - - - -/** - * call for every interface in the list the runDHCPCD method. - * - * @param interfaces - * list of interface names. - */ -void NetworkDiscovery::runDHCPCD(QList &interfaces) { - foreach(QString nI, interfaces) - { - runDHCPCD(nI); - } -} - - - -/** - * start a cdhcpcd process with the interface name as last argument. - * - * @param interface - * name of an interface. - */ -void NetworkDiscovery::runDHCPCD(QString interface) { - emit updateIfStatus(interface, "start DHCP"); - _dhcpcdArguments.append(interface); - QProcess * p = new QProcess(this); - - qxtLog->debug() << _tag << " start cdhcpcd with arguments: " << _dhcpcdArguments; - - _clientProcessToIfNameMap.insert(p, interface); - p->start(_pathToDhcpcdExe, _dhcpcdArguments); - connect(p, SIGNAL(started()), this, SLOT(handleProcessStarted())); - connect(p, SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(handleProcessFinished(int, QProcess::ExitStatus))); - _dhcpcdArguments.removeLast(); -} - - - -/** - * This Method is called when a process is started. - * - * This Method is called when a process is started. - * It prints the message: "process started for interface: ". - */ -void NetworkDiscovery::handleProcessStarted() { - QProcess* p = qobject_cast (QObject::sender()); - QString ifName = _clientProcessToIfNameMap.value(p, "ifName"); - qxtLog->debug() << _tag << " process started for interface: " << ifName; -} - - - -/** - * This Method is called when a process is finished. - * - * This Method is called when a process is finished. This slot is connected - * with the signal finished() of the QProcess class. - * If the process finishes, it will be checked if the process exited normal - * or if an unexpected error occurred. For this, we determine the sender (which is a - * QProcess), get the corresponding interface (which is stored in a map), and check - * the exitCode. Further actions are taken according to the exitCode check. - * Normal exit: - * emit changeProgressBar() to 100% - * emit updateIfStatus() to check connection - * checkConnectivity() @see NetworkDiscovery::checkConnectivity() - * Unexpected exit: - * emit updateIfStatus() to process exited unexpected - * - * @param exitCode - * - * @param exitStatus - * - * @return bool - * returns true: if the interface name i starts with a letter in the blacklist. - * - * returns false: else - * - * @see NetworkDiscovery::getListOfNetworkInterfaces() - */ -void NetworkDiscovery::handleProcessFinished(int exitCode, - QProcess::ExitStatus exitStatus) { - - QProcess* p = qobject_cast (QObject::sender()); - QString ifName = _clientProcessToIfNameMap.value(p, "ifName"); - _numberOfProcesses = _numberOfProcesses - 1; - if (!_blocked) { //_blocked becomes true, if _userChoice is false and we already found a usable interface - if (ifName.compare("ifName") == 0) { - qxtLog->debug() << _tag << " haven't found process!"; - } else { - qxtLog->debug() << _tag << " process for interface " << ifName - << " finished " << " exit code: " << exitCode - << " exit status " << exitStatus; - if (exitCode > 0) { - qxtLog->debug() << _tag << " process exited unexpected: " - << p->errorString(); - emit updateIfStatus(ifName, "process exited unexpected" - + p->errorString()); - } else { - qxtLog->debug() << _tag << " process normal exit "; - emit - changeProgressBarValue(ifName, 100); - emit - updateIfStatus(ifName, "check connectivity"); - if (checkConnectivity(ifName)) { - emit connectionEstablished(ifName); - if (!_userChoice) { - // blockiere jeden weiteren check - _blocked = true; - emit allProcessesFinished(); - } - } - } - } - if (!_blocked) { //_blocked becomes true, if _userChoice is false and we found a usable interface - QLocalSocket *client = _ifNameToClient.value(ifName, 0); - if (client != 0) { - handleNewInput(client); - } - //_numberOfProcesses = _numberOfProcesses - 1; && _userChoice - if (_numberOfProcesses <= 0) { - emit allProcessesFinished(); - } - } - } else { - qxtLog->debug() << _tag << " already blocked"; - emit updateIfStatus(ifName, "finished DHCP"); - } -} - - - -/** - * checks the connectivity. tries to open a TCP connection to the - * server (see _serverIp). For this it adjusts the routing table. - * (sets the gateway of the interface as default gateway) - * Gateway is written into the dhcpcd config file of this interface. - * (see DEFAULT_INTERFACE_CONF_LOCATION "/var/tmp/conf_") - * - * @param ifName - * name of a interface. - * - * @return - * true: connection is possible - * false: connection not possible - */ -bool NetworkDiscovery::checkConnectivity(QString ifName) { - int mss = 0; - - // get gateway address - QString pathToGatewayFile(DEFAULT_INTERFACE_CONF_LOCATION); - pathToGatewayFile += ifName; - interfaceconfiguration* ifConf; - if (!_ifcMap.contains(ifName)) { - ifConf = new interfaceconfiguration(); - _ifcMap.insert(ifName, ifConf); - } - else { - ifConf = _ifcMap.value(ifName); - } - ifConf->readConfigOutOfFile(pathToGatewayFile); - - // replace default route - qxtLog->debug() << _tag << "replace default route"; - _networkManager->replaceDefaultRoute(ifName, - ifConf->getGateway(), mss, AF_INET); - - if (checkConnectivityViaTcp(_serverIp)) { - qxtLog->debug() << _tag << " passed connectivity check! for interface " << ifName; - emit - updateIfStatus(ifName, "connection possible"); - return true; - } else { - qxtLog->debug() << _tag << " failed connectivity check! for interface " << ifName; - emit - updateIfStatus(ifName, "connection not possible"); - return false; - } -} - - - -/**/ -bool NetworkDiscovery::checkConnectivityViaTcp() { - return checkConnectivityViaTcp(_serverIp); -} - - - -/** - * try to open a tcp connection to the server - * - * @param server - * a ip address. - * - * @return - * true: connection is possible - * false: connection not possible - */ -bool NetworkDiscovery::checkConnectivityViaTcp(QString server) { - // check connectivity via tcp connection - qxtLog->debug() << _tag << " check connectivity to server: " << server; - // do host lookup - //QHostInfo hostInfo = QHostInfo::fromName(server); - QTcpSocket *tcpSocket = new QTcpSocket(this); - //qxtLog->debug() << _tag << " hostInfo first address: " << hostInfo.addresses().first().toString(); //hostInfo.addresses().first() - tcpSocket->connectToHost(server, 80); - if (!tcpSocket->waitForConnected(500)) { - qxtLog->debug() << _tag << tcpSocket->errorString(); - _errorStr += tcpSocket->errorString(); - return false; - } else { - return true; - } - delete tcpSocket; -} - - - -/** - * same function as handleNewInput() but with a client as parameter. - * - * @param cleint - * a client - */ -void NetworkDiscovery::handleNewInput(QLocalSocket * client) { - qxtLog->debug() << _tag << "last read before exit"; - while (client->canReadLine()) { - QString data(client->readLine()); - - data = data.trimmed(); - qxtLog->debug() << _tag << data; - QStringList lines = data.split("\n"); - - for (int i = 0; i < lines.length(); i++) { - handleNewInputLine(client, lines.at(i)); - } - } -} - - - -/** - * This method is connected to the readyRead Signal of the QLocalSocket - * client. - * send an ACK to the client with every received message. - */ -void NetworkDiscovery::handleNewInput() { - QLocalSocket* socket = qobject_cast (QObject::sender()); - - QLocalSocket * client = _clients.value(socket); - QString data(client->read(DHCP_MESSAGE_SIZE)); - data = data.trimmed(); - QStringList lines = data.split("\n"); - for (int i = 0; i < lines.length(); i++) { - handleNewInputLine(client, lines.at(i)); - } -} - - - -/** - * This Method processes the send messages. - * - * This Method processes the send messages. It splits the line - * into several components. Those components are: - * interface: interface name ==> indicates the process who send the message - * s_state: is the number representation of syslog.h LOG levels - * s_subState: is the number representation of the dhcp.c DHCP states (1 - 8) plus - * the status. h states (9 - ..) - * msg: is a message which can contain additional informations - * - * According to the s_state and s_subState we emit the changeProgressBarValue() signal - * with different values. - * - * @param client - * the client who send the message - * - * @param data - * the message. (format ;;; ) - */ -void NetworkDiscovery::handleNewInputLine(QLocalSocket * client, QString data) { - - QString logMsg(data); - QString interface = logMsg.section(";", 0, 0); - QString s_state = logMsg.section(";", 1, 1); - QString s_subState = logMsg.section(";", 2, 2); - QString msg = logMsg.section(";", 3, 3); - int st = s_state.trimmed().toInt(); - int sst = s_subState.trimmed().toInt(); - //qxtLog->debug() << _tag << logMsg; - - if (_ifNameToClient.size() < _numberOfProcesses && !_ifNameToClient.contains( - interface)) { - _ifNameToClient.insert(interface, client); - } - - switch (st) { - case LOG_INFO: - switch (sst) { - case DHCP_DISCOVER: - emit changeProgressBarValue(interface, 10); - qxtLog->debug() << _tag << " " << interface << " send discover"; - break; - case DHCP_OFFER: - emit changeProgressBarValue(interface, 20); - qxtLog->debug() << _tag << " " << interface << " got offer"; - break; - case DHCP_REQUEST: - emit changeProgressBarValue(interface, 30); - qxtLog->debug() << _tag << " " << interface << " send request"; - break; - case DHCP_ACK: - emit changeProgressBarValue(interface, 40); - qxtLog->debug() << _tag << " " << interface << " ack"; - break; - case DHCP_NAK: - emit changeProgressBarValue(interface, 40); - qxtLog->debug() << _tag << " " << interface << " nak"; - break; - case DHCPCD_ARP_TEST: - emit changeProgressBarValue(interface, 50); - qxtLog->debug() << _tag << " " << interface << " do arp test"; - break; - case DHCP_DECLINE: - emit changeProgressBarValue(interface, 60); - break; - case DHCP_RELEASE: - qxtLog->debug() << _tag << " " << interface << " release"; - break; - case DHCP_INFORM: - break; - case DHCPCD_CONFIGURE: - emit changeProgressBarValue(interface, 70); - qxtLog->debug() << _tag << " " << interface << " do configure interface"; - break; - case DHCPCD_WRITE: - emit changeProgressBarValue(interface, 80); - qxtLog->debug() << _tag << " " << interface << " write conf file"; - break; - case DHCPCD_EXIT: - emit changeProgressBarValue(interface, 100); - qxtLog->debug() << _tag << " " << interface << " exiting"; - break; - case DHCPCD_LOG: - qxtLog->debug() << _tag << " received dhcpcd log: " << msg; - default: - qxtLog->debug() << _tag << " received unknown substatus: " << msg; - break; - } - break; - case LOG_ERR: - qxtLog->debug() << _tag << " received error: " << msg; - break; - default: - qxtLog->debug() << _tag << " " << logMsg; - break; - } -} - - - -/** - * replace the default route. sets af automatically to AF_INET - * - * @param ifName - * interface name - * - * @param gateway - * gateway address - * - * @param mss - * mss value (i think this is the metric. in most cases this value is 0) - */ -int NetworkDiscovery::ip4_replaceDefaultRoute(QString ifName, QString gateway, int mss) { - return _networkManager->replaceDefaultRoute(ifName, gateway, mss, AF_INET); -} - - - -/** - * replace the dhcp configuration with the manual config, entered by the user. - * if we can not establish a connection with the entered values, reset to the old - * dhcp values. - * - * @param result - * a json object formated string. - * - * @return - * 0 if everything ok - */ -int NetworkDiscovery::ip4_setManualConfiguration(QVariantMap result) { - QList dns; - dns.append(result["dns"].toString()); - _networkManager->ip4_setManualConfiguration(result["ifname"].toString(), - result["ipaddr"].toString(), result["netmask"].toString(), - result["broadcast"].toString(), result["gateway"].toString(), 0, - AF_INET, "/etc/", dns); - - qxtLog->debug() << _tag << " set man conf. and check connectivity"; - - if (!checkConnectivityViaTcp(_serverIp)) { - qxtLog->debug() << _tag << " no connectivity. reset conf."; - interfaceconfiguration * ifc = _ifcMap.value( - result["ifname"].toString(), NULL); - if (ifc != NULL) { - dns.clear(); - dns = ifc->getDnsservers().trimmed().split(" "); - _networkManager->ip4_setManualConfiguration( - result["ifname"].toString(), ifc->getIpAddress(), - ifc->getNetmask(), ifc->getBroadcast(), ifc->getGateway(), - 0, AF_INET, "/etc/", dns); - } - - return 0; - } - qxtLog->debug() << _tag << " emit signal continueBootWithoutCheck(" << result["ifname"].toString() << ")"; - emit - continueBootWithoutCheck(result["ifname"].toString()); - return 0; -} - - - -/** - * returns the gateway address, written into the dhcp config file. - * - * @param ifName - * name of the interface. - * - * @return - * gateway address as string. or empty string if no interface config was found. - */ -QString NetworkDiscovery::getGatewayForInterface(QString ifName) { - interfaceconfiguration * ifConf = _ifcMap.value(ifName, NULL); - if (ifConf != NULL) - { - return ifConf->getGateway(); - } - else { - qxtLog->debug() << _tag << " could not find interface configuration"; - return ""; - } - -} - - - -/** - * reads the log file. - * - * @return the log file as one string. - */ -QString NetworkDiscovery::readLogFile() { - // path to log file is in _pathToLogFile. initialized in initAndRun(). - QString retval("the log file\n"); - QFile logFile(_pathToLogFile); - if (logFile.exists()) { - if (logFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - while (!logFile.atEnd()) { - retval.append(logFile.readLine()); - } - } - else { - qxtLog->debug() << _tag << " could not open log file"; - retval = "could not open log file"; - } - } - else { - qxtLog->debug() << _tag << " log file does not exist at: " << _pathToLogFile; - retval = " log file does not exist at: " + _pathToLogFile; - } - return retval; - -} - - -/**/ -void NetworkDiscovery::killDHCPCD() { - qxtLog->debug() << " kill cdhcpcd processes"; - QProcess * p = new QProcess(this); - p->start("killall cdhcpcd"); - p->waitForFinished(); - if (p->exitCode() > 0) - qxtLog->debug() << _tag << " [tryAgain] " << p->errorString(); - - delete p; -} - - - -/**/ -void NetworkDiscovery::prepareTryAgain() { - // kill all cdhcpcd processes - killDHCPCD(); - - /* - foreach(Q_PID pid , _pidsList) { - if (kill(pid,SIGKILL) <= -1) - qDebug() << _tag << " error: trying to kill process: " << pid << " error: " << strerror(errno); - } - */ - // reset everything - delete _networkManager; - delete _server; - foreach(QProcess* p, _clientProcessToIfNameMap.keys()) - { - delete p; - } - foreach(interfaceconfiguration* i, _ifcMap.values()) - { - delete i; - } -} - - - -/* - *TODO: to be bug fixed - *TODO: do it with kill and not QProcess("killall cdhcpcd") - */ -void NetworkDiscovery::tryAgain() { - prepareTryAgain(); - initAndRun(_serverIp, _userChoice, _autoUp, _pathToLogFile, _serverPath, DEFAULT_PATHTODHCPCDEXE); -} - - - -/**/ -QVariantMap NetworkDiscovery::getInterfaceConfig(QString ifName) { - QVariantMap jsonObj; - QList dns; - interfaceconfiguration * ifc = _ifcMap.value(ifName, NULL); - if (ifc != NULL) { - jsonObj.insert("ipaddr",ifc->getIpAddress()); - jsonObj.insert("netmask",ifc->getNetmask()); - jsonObj.insert("broadcast",ifc->getBroadcast()); - jsonObj.insert("gateway",ifc->getGateway()); - - dns.clear(); - dns = ifc->getDnsservers().trimmed().split(" "); - jsonObj.insert("dns",dns.first()); - } - return jsonObj; -} - - - -/** - * connected to the new client arrived signal. - * connects the client readyRead signal with the handleNewInput slot. - */ -void NetworkDiscovery::handleNewConnection() { - qxtLog->debug() << _tag << " New Connection arrived"; - - /*QLocalSocket **/ - _client = _server->nextPendingConnection(); - _clients.insert(_client, _client); - connect(_client, SIGNAL(disconnected()), this, - SLOT(handleClientDisconnect())); - connect(_client, SIGNAL(readyRead()), this, SLOT(handleNewInput())); -} - - - -/** - * called when a client disconnects. - */ -void NetworkDiscovery::handleClientDisconnect() { - QLocalSocket* socket = qobject_cast (QObject::sender()); - - QLocalSocket * client = _clients.value(socket); - - qxtLog->debug() << _tag << " disconnect client"; - handleNewInput(client); - client->deleteLater(); -} - - - -/** - * This Method implements a blacklist. - * - * This Method implements a blacklist. We check the fist character - * of the interface name. if this letter is in the list, we return true. - * True means, that this interface won't be put into the result list of - * getListOfNetworkInterfaces(). - * - * @param i - * is a interface name. - * - * @return bool - * returns true: if the interface name i starts with a letter in the blacklist. - * - * returns false: else - * - * @see NetworkDiscovery::getListOfNetworkInterfaces() - */ -bool NetworkDiscovery::checkBlackList(QString i) { - if (i.startsWith("v", Qt::CaseInsensitive)) { - return true; - } else if (i.startsWith("d", Qt::CaseInsensitive)) { - return true; - } else { - return false; - } -} - - - -/**/ -QString NetworkDiscovery::GetErrorStr() { - return _errorStr; -} - - - -////////////////////////////////////////////////////////////////////////////////////// - -/** - * not used so far. checks the carrier state using the sysfs library. - * if carrier = 1 ==> the interface is running. - * interfaces have to be up in order to get right results. - * - * @param interface - * name of the interface - */ -bool NetworkDiscovery::checkCarrierState(QString interface) { - - qxtLog->debug() << _tag << "check carrier state for interface " << interface; - QByteArray ba = interface.toAscii(); - const char * iface = ba.data(); - - struct sysfs_class_device *class_device = sysfs_open_class_device("net", - iface); - struct dlist *attrlist = sysfs_get_classdev_attributes(class_device); - if (attrlist != NULL) { - struct sysfs_attribute *attr = NULL; - dlist_for_each_data(attrlist, attr, struct sysfs_attribute) { - if (strcmp("carrier", attr->name) == 0) { - QString value(attr->value); - bool ok = false; - bool * pok = &ok; - int v = value.toInt(pok); - if (*pok) { - if (v == 1) { - qxtLog->debug() - << "carrier is 1. Cable is plugged. return true"; - return true; - } else { - qxtLog->debug() - << "carrier is 0. Cable is unplugged. return false"; - return false; - } - } else { - qxtLog->debug() << _tag << "conversion error"; - } - } - } - } else { - qxtLog->debug() << _tag << "attrlist is Null"; - } - sysfs_close_class_device(class_device); - - return true; -} diff --git a/src/networkdiscovery.h b/src/networkdiscovery.h deleted file mode 100644 index c422b18..0000000 --- a/src/networkdiscovery.h +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - */ - - - -#ifndef NetworkDiscovery_H -#define NetworkDiscovery_H - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "loggerengine.h" -#include "interfaceconfiguration.h" -#include "networkmanager.h" - - -#include "dhcp.h" - -#include "../common/fbgui.h" - - - -#define DEFAULT_PATHTODHCPCDEXE "/bin/cdhcpcd" - -class NetworkDiscovery: public QObject { -Q_OBJECT - -public: - NetworkDiscovery(QObject *parent=0); - ~NetworkDiscovery(); - - void initAndRun(QString serverIp, bool userChoice, - bool autoUp, - QString pathToLogFile, - QString serverPath = DEFAULT_QTSOCKETADDRESS, - QString pathToExe = DEFAULT_PATHTODHCPCDEXE, - QStringList* args = NULL); - int ip4_replaceDefaultRoute(QString ifName, QString gateway, int mss); - QString getGatewayForInterface(QString ifName); - - int ip4_setManualConfiguration(QVariantMap result); - QString readLogFile(); - void tryAgain(); - void prepareTryAgain(); - bool checkConnectivity(QString ifName); - bool checkConnectivityViaTcp(); - QVariantMap getInterfaceConfig(QString ifName); - QString GetErrorStr(); - -public slots: - void handleNewConnection(); - void handleNewInput(); - void handleNewInputLine(QLocalSocket * client, QString data); - void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); - void handleProcessStarted(); - void handleClientDisconnect(); - - void slotReadyForRun(); - - void checkForIsRunning(); - - -signals: - void addInterface(const QString &ifName); - void changeProgressBarValue(const QString & ifName, const int $newValue); - void connectionEstablished(QString ifName); - void abortBoot(QString msg); - void updateIfStatus(QString ifName, QString status); - void updateStatus(QString status); - void allProcessesFinished(); - void continueBoot(QString ifName); - void continueBootWithoutCheck(QString ifName); - void setManualConfInterfaces(QString jsonArr); - - void readyForRun(); - -private: - QString _tag; - QLocalServer *_server; - QMap _clients; - QLocalSocket *_client; - QMap _ifNameToClient; - QMap _clientProcessToIfNameMap; - QString _serverPath; - QString _pathToDhcpcdExe; - QStringList _dhcpcdArguments; - int _numberOfProcesses; - NetworkManager* _networkManager; - bool _userChoice; - bool _blocked; - bool _autoUp; - QString _serverIp; - QString _pathToLogFile; - QList _ifUpList; - QList _ifDownList; - int _ifUpCountdown; - QTimer*_timer; - QList _pidsList; - QString _errorStr; - QMap _ifcMap; - void mainWork(); - - void killDHCPCD(); - - void handleNewInput(QLocalSocket * client); - - void runDHCPCD(QList &interfaces); - void runDHCPCD(QString interface); - - bool checkCarrierState(QString interface); - bool checkConnectivityViaTcp(QString server); - - bool checkBlackList(QString i); - - void getListOfNetworkInterfaces(); - void getListOfNetworkInterfacesWithAutoUp(); - - -}; - -#endif // NetworkDiscovery_H diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp deleted file mode 100644 index 2dc774f..0000000 --- a/src/networkmanager.cpp +++ /dev/null @@ -1,681 +0,0 @@ -/** - * @class NetworkManager - * - * @brief Manages the network configurations like setting new default routes. - * - * Manages the network configurations like setting new default routes. - * It provides methods for ipv4 and some method for ipv6. - * - */ - - - -#include "networkmanager.h" - -NetworkManager::NetworkManager() { - // TODO Auto-generated constructor stub - _tag = "[nd:NetworkManager]"; -} - - - -NetworkManager::~NetworkManager() { - // TODO Auto-generated destructor stub -} - - - -/** - * This method adds /replaces the default route. - * This method adds /replaces the default route. - * To keep it modular, it is possible - * to specify an ip address family. - * - * @param ifName - * the interface name - * - * @param gateway - * the gateway address (e.g: 192.168.0.254) - * @param mss - * the mss. - * @param af - * specify the family type of the ip address. - * possible values are: AF_INET for an IPv4 address - * AF_INET6 for an IPv6 address - * - - * @return - * return -1 if an error happened. - * return 0 if everything was ok. - */ -int NetworkManager::replaceDefaultRoute(QString ifname, QString gateway, - int mss, int af) { - struct nl_cache *cache; - struct nl_handle* rtsock; - struct nl_addr * gw; - struct rtnl_route * route; - int retval, iface_idx; - - QByteArray ba_ifn = ifname.toAscii(); - char * ifn = ba_ifn.data(); - - QByteArray ba_gw = gateway.toAscii(); - char * gwaddr = ba_gw.data(); - - qDebug() << _tag << "---doRoute() gwaddr" << gwaddr; - - if (!(gw = nl_addr_parse(gwaddr, af))) { - qDebug() << _tag << "Invalid router address given:" << gwaddr; - return -1; - } - - rtsock = nl_handle_alloc(); - nl_connect(rtsock, NETLINK_ROUTE); - - if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) { - qDebug() << _tag << "error with link cache alloc \n"; - } - - iface_idx = rtnl_link_name2i(cache, ifn); - - route = rtnl_route_alloc(); - rtnl_route_set_scope(route, RT_SCOPE_UNIVERSE); - rtnl_route_set_gateway(route, gw); - rtnl_route_set_oif(route, iface_idx); - - if (mss > 0) { - rtnl_route_set_metric(route, RTAX_ADVMSS, mss); - } - - retval = rtnl_route_add(rtsock, route, NLM_F_REPLACE); - qDebug() << _tag << "return value:" << retval << ":" << strerror(-retval); - - rtnl_route_put(route); - nl_addr_put(gw); - nl_handle_destroy(rtsock); - - return retval; -} - - - -/**/ -int NetworkManager::ip6_addRoute(const char *iface, - const struct in6_addr *ip6_dest, int ip6_prefix, - const struct in6_addr *ip6_gateway, int metric, int mss) { - struct nl_cache *cache; - struct nl_handle *nlh; - struct rtnl_route *route; - struct nl_addr *dest_addr; - struct nl_addr *gw_addr = NULL; - int err, iface_idx; - - nlh = nl_handle_alloc(); - nl_connect(nlh, NETLINK_ROUTE); - - if ((cache = rtnl_link_alloc_cache(nlh)) == NULL) { - //qDebug() << _tag << "error with link cache alloc \n"; - printf("error with link cache alloc \n"); - } - - iface_idx = rtnl_link_name2i(cache, iface); - - route = rtnl_route_alloc(); - - /* Destination */ - dest_addr = nl_addr_build(AF_INET6, (struct in6_addr *) ip6_dest, - sizeof(*ip6_dest)); - nl_addr_set_prefixlen(dest_addr, (int) ip6_prefix); - - rtnl_route_set_dst(route, dest_addr); - nl_addr_put(dest_addr); - - /* Gateway */ - if (ip6_gateway && !IN6_IS_ADDR_UNSPECIFIED (ip6_gateway)) { - gw_addr = nl_addr_build(AF_INET6, (struct in6_addr *) ip6_gateway, - sizeof(*ip6_gateway)); - if (gw_addr) { - rtnl_route_set_gateway(route, gw_addr); - rtnl_route_set_scope(route, RT_SCOPE_UNIVERSE); - } else { - rtnl_route_put(route); - return -1; - } - } - - /* Metric */ - if (metric) - rtnl_route_set_prio(route, metric); - - /* Add the route */ - err = rtnl_route_add(nlh, route, 0); - if (err == -ESRCH && ip6_gateway) { - /* Gateway might be over a bridge; try adding a route to gateway first */ - struct rtnl_route *route2; - - route2 = create_route(iface_idx, mss); - if (route2) { - /* Add route to gateway over bridge */ - rtnl_route_set_dst(route2, gw_addr); - err = rtnl_route_add(nlh, route2, 0); - if (!err) { - /* Try adding the route again */ - err = rtnl_route_add(nlh, route, 0); - if (err) - rtnl_route_del(nlh, route2, 0); - } - rtnl_route_put(route2); - } - } - - if (gw_addr) - nl_addr_put(gw_addr); - - if (err) { - //nm_warning ("Failed to set IPv6 route on '%s': %s", iface, nl_geterror ()); - rtnl_route_put(route); - route = NULL; - } - - return 0; -} - - - -struct rtnl_route * NetworkManager::create_route (int iface_idx, int mss) -{ - struct rtnl_route *route; - - route = rtnl_route_alloc (); - if (route) { - rtnl_route_set_oif (route, iface_idx); - - if (mss && rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0) { - //nm_warning ("Could not set mss"); - } - } else - //nm_warning ("Could not allocate route"); - - return route; -} - - - -/** - * The method brings an interface up. - * - * @param ifname - * the name of the interface - * - * @return - * 0 -> success - * -1 -> error - */ -int NetworkManager::bringInterfaceUP(QString ifname) { - return bringInterfaceUpDown(ifname, true); -} - - - -/** - * The method brings an interface down. - * - * @param ifname - * the name of the interface - * - * @return - * 0 -> success - * -1 -> error - */ -int NetworkManager::bringInterfaceDown(QString ifname) { - return bringInterfaceUpDown(ifname, false); -} - - - -/** - * This method brings an interface up or down. - * - * @param ifname - * is a string which contains the interface name which is going down or up. - * - * @param up - * is a bool. true means. we bring the interface up. - * false meand. we bring the interface down. - * @return - * 0 if everything is ok - * else an error - */ -int NetworkManager::bringInterfaceUpDown(QString ifname, bool up) { - struct nl_cache *cache; - struct nl_handle* rtsock; - struct rtnl_link* request = NULL; - struct rtnl_link* old = NULL; - int retval; - - QByteArray ba_ifn = ifname.toAscii(); - char * ifn = ba_ifn.data(); - - if (!(request = rtnl_link_alloc())) { - qDebug() << _tag << "error. couldn't allocate a rtnl link"; - return -1; - } - - rtsock = nl_handle_alloc(); - nl_connect(rtsock, NETLINK_ROUTE); - - if (up) { - rtnl_link_set_flags(request, IFF_UP); - } else { - rtnl_link_unset_flags(request, IFF_UP); - } - - if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) { - qDebug() << _tag << "error with link cache alloc "; - } - - old = rtnl_link_get_by_name(cache, ifn); - if (old) { - qDebug() << _tag << "change link"; - retval = rtnl_link_change(rtsock, old, request, 0); - } else { - qDebug() << _tag << "change failed"; - retval = -1; - qDebug() << _tag << "return value:" << retval << ":" << strerror(-retval); - } - - rtnl_link_put(old); - rtnl_link_put(request); - nl_handle_destroy(rtsock); - - return retval; -} - - - -/** - * This method is used when the manual configuration is needed. - * - * This method is used when the manual configuration is needed. - * First we bring up the interface. Than we configure the interface with - * our manual entered configuration dates. - * After that we replace the old default route with the new and - * write a resolv.conf. - * - * @param ifname - * name of the interface which we are about to configure. - * - * @param ipAddress - * the new IP-Address. - * - * @param netmask - * the netmask of the IP-Address. - * - * @param broadcast - * the broadcast address. - * @param gateway - * the gateway address. - * @param metric - * do not exactly know why we need this. in most cases this should be 0. - * @param af - * the address type. Either AF_INET for IPv4 or AF_INET6 for IPv6. - * @param pathToResolvConf - * the path to the resolf.conf file. in most cases "/etc/". - * @param nameServer - * the name server addresses. - */ -int NetworkManager::ip4_setManualConfiguration(QString ifname, QString ipAddress, QString netmask, - QString broadcast, QString gateway, int metric, int af, QString pathToResolvConf, QList nameServer) { - - //bring the interface up - bringInterfaceUP(ifname); - //set configuration - ip4_configureInterface(ifname, ipAddress, broadcast, netmask,af); - //set default route - replaceDefaultRoute(ifname, gateway, metric, af); - //write resolv.conf - writeResolvConf(pathToResolvConf, ifname, nameServer); - return 0; -} - - - -int NetworkManager::ip4_configureInterface(QString ifname, QString ipAddress, - QString broadcast, QString netmask, int af) { - - struct nl_cache *cache; - struct nl_handle* rtsock; - struct nl_addr * local; - struct rtnl_addr * addr = NULL; - int retval = 0; - int iface_idx, err, prefixLength; - - QByteArray ba_ifn = ifname.trimmed().toAscii(); - char * ifn = ba_ifn.data(); - - QByteArray ba_ip = ipAddress.trimmed().toAscii(); - char * ipaddr = ba_ip.data(); - - QByteArray ba_bc = broadcast.trimmed().toAscii(); - char * bcaddr = ba_bc.data(); - - rtsock = nl_handle_alloc(); - nl_connect(rtsock, NETLINK_ROUTE); - - if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) { - qDebug() << _tag << "error with link cache alloc"; - return -1; - } - - iface_idx = rtnl_link_name2i(cache, ifn); - - if (!(addr = rtnl_addr_alloc())) { - qDebug() << _tag << "error with addr alloc"; - return -1; - } - - local = nl_addr_parse(ipaddr, af); - err = rtnl_addr_set_local(addr, local); - nl_addr_put(local); - if (err != 0) { - qDebug() << _tag << "error with set local addr"; - } - - prefixLength = ip4_netmaskToPrefix(ipAddress,netmask); - qDebug() << _tag << "prefix length:" << prefixLength; - rtnl_addr_set_prefixlen(addr, prefixLength); - - local = nl_addr_parse(bcaddr, af); - err = rtnl_addr_set_broadcast(addr, local); - nl_addr_put(local); - if (err != 0) { - qDebug() << _tag << "error with set broadcast addr"; - } - - rtnl_addr_set_ifindex(addr, iface_idx); - - - retval = sync_address(ifn, iface_idx, af, addr); - if(retval < 0) { - qDebug() << _tag << "error in sync_address"; - } - rtnl_addr_put(addr); - - return retval; -} - - - -/** - * This Method returns the length of the IP-Address netmask prefix. - * - * @param ipAddr - * the IP-address - * - * @param netmask - * the netmask of the IP-address. - * @return - * the length of the IP-Address netmask prefix - */ -int NetworkManager::ip4_netmaskToPrefix(QString ipAddr, QString netmask) { - int retval = -1; - QNetworkAddressEntry nae; - - if (netmask == "") { - qDebug() << _tag << "error: netmask is empty"; - return retval; - } - nae.setIp(QHostAddress(ipAddr)); - nae.setNetmask(QHostAddress(netmask.trimmed())); - retval = nae.prefixLength(); - - return retval; -} - - - -int NetworkManager::ip6_addAddress(struct ip6_addr* ip6Addr, const char *iface) { - int num_addrs, i, iface_idx; - struct rtnl_addr* addr = NULL; - struct nl_cache *cache; - struct nl_handle* rtsock; - - rtsock = nl_handle_alloc(); - nl_connect(rtsock, NETLINK_ROUTE); - - if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) { - qDebug() << _tag << "error with link cache alloc"; - return -1; - } - - iface_idx = rtnl_link_name2i(cache, iface); - - addr = ip6AddrToRtnlAddr(ip6Addr); - if (!addr) { - //nm_warning("couldn't create rtnl address!\n"); - return -1; - } - rtnl_addr_set_ifindex(addr, iface_idx); - - return sync_address(iface, iface_idx, AF_INET6, addr); -} - - - -/**/ -struct rtnl_addr* NetworkManager::ip6AddrToRtnlAddr(struct ip6_addr* ip6Addr) { - struct rtnl_addr *addr; - bool success = true; - - if (!(addr = rtnl_addr_alloc())) - return NULL; - - success = (nlAddrToRtnlAddr(ip6Addr, addr) >= 0); - - if (!success) { - rtnl_addr_put(addr); - addr = NULL; - } - - return addr; -} - - - -/**/ -struct nl_addr* NetworkManager::ip6AddrToNlAddr(const struct ip6_addr *ip6Addr) { - struct nl_addr * nla = NULL; - - if (!(nla = nl_addr_alloc(sizeof(struct in6_addr)))) - return NULL; - nl_addr_set_family(nla, AF_INET6); - nl_addr_set_binary_addr(nla, (struct in6_addr *) ip6Addr, sizeof(struct in6_addr)); - - return nla; -} - - - -/**/ -int NetworkManager::nlAddrToRtnlAddr( - const struct ip6_addr* ip6Addr, struct rtnl_addr* addr) { - struct nl_addr * local = NULL; - int err = 0; - - local = ip6AddrToNlAddr(ip6Addr); - err = rtnl_addr_set_local(addr, local); - nl_addr_put(local); - - return -err; -} - - - -/** - * delete all addresses of this interface but not the one we just set - * - * @return - * -1 if something went wrong. else 0 - */ -int NetworkManager::sync_address(const char *iface, int ifindex, int family, - struct rtnl_addr *addr) { - - struct nl_handle *nlh; - struct nl_cache *addr_cache; - struct rtnl_addr *filter_addr, *match_addr; - struct nl_object *match; - struct nl_addr *nladdr; - int err; - char buf[INET6_ADDRSTRLEN + 1]; - - nlh = nl_handle_alloc(); - nl_connect(nlh, NETLINK_ROUTE); - - if (!nlh) - return -1; - - addr_cache = rtnl_addr_alloc_cache(nlh); - - if (!addr_cache) - return -1; - - filter_addr = rtnl_addr_alloc(); - if (!filter_addr) { - nl_cache_free(addr_cache); - return -1; - } - rtnl_addr_set_ifindex(filter_addr, ifindex); - if (family) - rtnl_addr_set_family(filter_addr, family); - - //nm_log_dbg (log_domain, "(%s): syncing addresses (family %d)", iface, family); - - /* Walk through the cache, comparing the addresses already on - * the interface to the addresses in addrs. - */ - for (match = nl_cache_get_first(addr_cache); match; match - = nl_cache_get_next(match)) { - int buf_valid = -1; - match_addr = (struct rtnl_addr *) match; - - /* Skip addresses not on our interface */ - if (!nl_object_match_filter(match, (struct nl_object *) filter_addr)) - continue; - - if (addr) { - if (addr && nl_object_identical(match, (struct nl_object *) addr)) { - continue; - } - } - - nladdr = rtnl_addr_get_local(match_addr); - - /* Don't delete IPv6 link-local addresses; they don't belong to NM */ - if (rtnl_addr_get_family(match_addr) == AF_INET6) { - struct in6_addr *tmp; - - if (rtnl_addr_get_scope(match_addr) == RT_SCOPE_LINK) { - //nm_log_dbg (log_domain, "(%s): ignoring IPv6 link-local address", iface); - continue; - } - - tmp = (in6_addr*) nl_addr_get_binary_addr(nladdr); - if (inet_ntop(AF_INET6, tmp, buf, sizeof(buf))) - buf_valid = 0; - } else if (rtnl_addr_get_family(match_addr) == AF_INET) { - struct in_addr *tmp; - - tmp = (in_addr *) nl_addr_get_binary_addr(nladdr); - if (inet_ntop(AF_INET, tmp, buf, sizeof(buf))) - buf_valid = 0; - } - - if (buf_valid == 0) { - //nm_log_dbg (log_domain, "(%s): removing address '%s/%d'", - // iface, buf, nl_addr_get_prefixlen (nladdr)); - } - - /* Otherwise, match_addr should be removed from the interface. */ - err = rtnl_addr_delete(nlh, match_addr, 0); - if (err < 0) { - //nm_log_err (log_domain, "(%s): error %d returned from rtnl_addr_delete(): %s", - // iface, err, nl_geterror ()); - qDebug() << _tag << "error with delete addr"; - } - } - - rtnl_addr_put(filter_addr); - nl_cache_free(addr_cache); - - /* Now add the remaining new addresses */ - if (!addr) - return -1; - - struct in6_addr *in6tmp; - struct in_addr *in4tmp; - int buf_valid = -1; - - nladdr = rtnl_addr_get_local(addr); - if (rtnl_addr_get_family(addr) == AF_INET6) { - in6tmp = (in6_addr*) nl_addr_get_binary_addr(nladdr); - if (inet_ntop(AF_INET6, in6tmp, buf, sizeof(buf))) - buf_valid = 0; - } else if (rtnl_addr_get_family(addr) == AF_INET) { - in4tmp = (in_addr*) nl_addr_get_binary_addr(nladdr); - if (inet_ntop(AF_INET, in4tmp, buf, sizeof(buf))) - buf_valid = 0; - } - - if (buf_valid == 0) { - //nm_log_dbg (log_domain, "(%s): adding address '%s/%d'", - //iface, buf, nl_addr_get_prefixlen (nladdr)); - qDebug() << _tag << "buf valid adding addr"; - } - - err = rtnl_addr_add(nlh, addr, 0); - if (err < 0) { - //nm_log_err (log_domain, - // "(%s): error %d returned from rtnl_addr_add():\n%s", - // iface, err, nl_geterror ()); - qDebug() << _tag << "error with add addr"<< strerror(-err); - } - - rtnl_addr_put(addr); - - return err; -} - - - -/** - * This method writes a resolv.conf file. - * - * @param path - * path to the resolv.conf file. (in most cases: /etc/) - * @param ifname - * name of the interface - * @param - * addresses of the nameserver - * - * @return - * return 0 if success - * else -1 - */ -int NetworkManager::writeResolvConf(QString path, QString ifname, QList nameServer){ - - QFile file(path + "resolv.conf"); - if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qDebug() << _tag << "error couldn't open file:" << path; - return -1; - } - QTextStream out(&file); - out << "# Generated by networkdiscovery manual configuration for interface " + ifname +"\n"; - foreach(QString ns, nameServer ) { - out << "nameserver " + ns +"\n"; - } - - file.close(); - - return 0; -} - diff --git a/src/networkmanager.h b/src/networkmanager.h deleted file mode 100644 index fbb8993..0000000 --- a/src/networkmanager.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - */ - - - -#ifndef NETWORKMANAGER_H_ -#define NETWORKMANAGER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -class NetworkManager: public QObject { -Q_OBJECT - -public: - NetworkManager(); - virtual ~NetworkManager(); - - int replaceDefaultRoute(QString ifname, QString gateway, int metric, - int af); - - int bringInterfaceUP(QString ifname); - int bringInterfaceDown(QString ifname); - - int ip4_setManualConfiguration(QString ifname, QString ipAddress, QString netmask, - QString broadcast, QString gateway, int metric, int af, QString pathToResolvConf, QList nameServer); - int ip4_configureInterface(QString ifname, QString ipAddress, - QString broadcast, QString netmask, int af); - - int ip6_addRoute(const char *iface, - const struct in6_addr *ip6_dest, int ip6_prefix, - const struct in6_addr *ip6_gateway, int metric, int mss); - int ip6_addAddress(struct ip6_addr* ip6Addr, const char *iface); - - int writeResolvConf(QString path, QString ifname, QList nameServer); - -private: - QString _tag; - int bringInterfaceUpDown(QString ifname, bool up); - int ip4_netmaskToPrefix(QString ipAddr, QString netmask); - - int sync_address(const char *iface, int ifindex, int family, - struct rtnl_addr *addr); - - struct rtnl_route* create_route (int iface_idx, int mss); - struct nl_addr* ip6AddrToNlAddr (const struct ip6_addr* ip6Addr); - int nlAddrToRtnlAddr (const struct ip6_addr* ip6Addr, struct rtnl_addr* addr); - struct rtnl_addr* ip6AddrToRtnlAddr(struct ip6_addr* ip6Addr); - - -}; - -#endif /* NETWORKMANAGER_H_ */ diff --git a/src/sysinfo.cpp b/src/sysinfo.cpp deleted file mode 100644 index 7d6ac92..0000000 --- a/src/sysinfo.cpp +++ /dev/null @@ -1,180 +0,0 @@ -#include "sysinfo.h" - -// ------------------------------------------------------------------------------------------------ -/** - * A empty constructor. - */ -SysInfo::SysInfo() { -} -// ------------------------------------------------------------------------------------------------ -/** - * A empty destructor. - */ -SysInfo::~SysInfo() { -} -// ------------------------------------------------------------------------------------------------ -/** - * This method returns system informations. - * - * This method returns system informations according to the parameter. - * This method can be called from the JavascriptInterface class with the - * method JavascriptInterface::getSysInfo(const QString& info). - * - * @param infoName - * Is of type QString. Defines which method will be called. Possible values are: - * - mbserial - * - usb - * - * @return QString - * the output of the called method or "info_error" if an error occurred - * (e. g. invalid parameter). - * - * @see JavascriptInterface::getSysInfo(const QString& info) - */ -const QString SysInfo::getInfo(const QString& infoName) { - qxtLog->debug() << "[sysinfo] requested " << infoName; - if (infoName == QString("mbserial")) - return getMainboardSerial(); - else if (infoName == QString("usb")) - return getUsbVendorIdProductIdSerialNumber(); - /* unknown code */ - qxtLog->debug() << "[sysinfo] unknown requested"; - return "info_error"; -} -// ----------------------------------------------------------------------------------------------- -// Mainboard / USB Infos using libsysfs -// ----------------------------------------------------------------------------------------------- -/** - * This method returns the Mainboard Serial Number. - * - * This method returns the Mainboard Serial Number. The mainboard serial - * number is used as part of the data to compute the hardwarehash of the - * client machine. To call this method use the - * SysInfo::getInfo(const QString& infoName) method with - * the parameter "mbserial" - * - * @return QString - * the mainboard serial or "mainboard_serial_error" if an error occurred. - * - * @see fbgui::generatePOSTData() - * @see SysInfo::getInfo(const QString& infoName) - */ -const QString SysInfo::getMainboardSerial() { - QString out = ""; - struct sysfs_class_device *class_device = sysfs_open_class_device("dmi", - "id"); - struct dlist *attrlist = sysfs_get_classdev_attributes(class_device); - struct sysfs_device *device = sysfs_get_classdev_device(class_device); - - if (attrlist != NULL) { - struct sysfs_attribute *attr = NULL; - dlist_for_each_data(attrlist, attr, struct sysfs_attribute) { - QVariantMap a; - if(QString(attr->name) == QString("board_serial")) { - out = QString(attr->value); - } - } - qxtLog->debug() << "[sysinfo] Mainboard Serial: " + out; - return out; - } - qxtLog->debug() - << "[sysinfo] Mainboard Serial: attrlist is null! return: mainboard_serial_error"; - sysfs_close_class_device(class_device); - return "mainboard_serial_error"; -} -// ------------------------------------------------------------------------------------------------ -/** - * This method returns inforamtions about connected usb devices. - * - * This method returns the inforamtions about connected usb devices - * as a json formated string. - * Those informations are: - * - the vendor - * - the vendorID - * - the product - * - the productID - * - the manufacturer - * - the serial number - * To call this method use the SysInfo::getInfo(const QString& infoName) - * method with the parameter "usb" - * - * @return QString - * all above described informations as a json formated string or "error" - * if an error occurred. - * - * @see SysInfo::getInfo(const QString& infoName) - */ -const QString SysInfo::getUsbVendorIdProductIdSerialNumber() { - - QString tag = "[sysinfo] Usb Serial:"; - QString out = ""; - QVariantList list; - - libusb_device **devs; - libusb_context *ctx = NULL; //a libusb session - ssize_t cnt; //holding number of devices in list - int r = 1; - r = libusb_init(&ctx); - if (r < 0) { - qxtLog->debug() << tag + "failed to initialise libusb"; - return "error"; - } - cnt = libusb_get_device_list(ctx, &devs); //get the list of devices - if (cnt < 0) { - qxtLog->debug() << tag + "Get Device Error"; //there was an error - } - qxtLog->debug() << tag + cnt + " Devices in list."; //print total number of usb devices - ssize_t i; //for iterating through the list# - for (i = 0; i < cnt; i++) { - //printdev(devs[i]); //print specs of this device - QVariantMap infos; - libusb_device *dev = devs[i]; - libusb_device_descriptor desc; - int re = libusb_get_device_descriptor(dev, &desc); - if (re < 0) { - qxtLog->debug() << tag + "failed to get device descriptor"; - return "error"; - } - infos.insert("vendorId", desc.idVendor); - infos.insert("productId", desc.idProduct); - unsigned char string[256]; - libusb_device_handle *handle; - re = libusb_open(dev, &handle); - if (re != 0) { - qxtLog->debug() << tag + "failed to get handler / fail to open device"; - return "error"; - } - re = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, - string, sizeof(string)); - if (re < 0) { - qxtLog->debug() << tag + "failed to get SerialNumber"; - return "error"; - } - infos.insert("serialnumber", QString((const char *) string)); - re = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, - sizeof(string)); - if (re < 0) { - qxtLog->debug() << tag + "failed to get Product"; - return "error"; - } - infos.insert("product", QString((const char *) string)); - re = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, - string, sizeof(string)); - if (re < 0) { - qxtLog->debug() << tag + "failed to get Product"; - return "error"; - } - infos.insert("manuacturer", QString((const char *) string)); - - list << infos; - libusb_close(handle); - } - libusb_free_device_list(devs, 1); //free the list, unref the devices in it - libusb_exit(ctx); //close the session - - /* - QByteArray json = serializer.serialize(list); - qxtLog->debug() << tag + "json object: " + json; - return json; - */ -} diff --git a/src/sysinfo.h b/src/sysinfo.h deleted file mode 100644 index c860cca..0000000 --- a/src/sysinfo.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2010,2011 - RZ Uni Freiburg - * Copyright (c) 2010,2011 - OpenSLX Project - * - * This program/file is free software distributed under the GPL version 2. - * See http://openslx.org/COPYING - * - * If you have any feedback please consult http://openslx.org/feedback and - * send your feedback to feedback@openslx.org - * - * General information about OpenSLX can be found under http://openslx.org - * - * - * Helper class to get system information. - * - */ - -#ifndef SYSINFO_H -#define SYSINFO_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "sysfs/libsysfs.h" -#include -#ifdef __cplusplus -} -#endif - -#include "fbgui.h" -//#include - -class SysInfo { -public: - SysInfo(); - ~SysInfo(); - // public access, valid infoName: "mbserial", "usb" - const QString getInfo(const QString& infoName); - -private: - // private system information readers - const QString getMainboardSerial(); - const QString getUsbVendorIdProductIdSerialNumber(); - - // JSon testing - //QJson::Serializer serializer; -}; - -#endif // SYSTINFO_H -- cgit v1.2.3-55-g7522