pax_global_header00006660000000000000000000000064122140115530014504gustar00rootroot0000000000000052 comment=03369a7678e6c565e3d2dddc06181438d34f8b5c Nagstamon-0.9.11/000077500000000000000000000000001221401155300135235ustar00rootroot00000000000000Nagstamon-0.9.11/COPYRIGHT000066400000000000000000000000661221401155300150200ustar00rootroot00000000000000Copyright (C) 2009 Henri Wahl Nagstamon-0.9.11/ChangeLog000066400000000000000000002520371221401155300153060ustar00rootroot000000000000002012-03-28 12:47 henriwww * Nagstamon/GUI.py: just another regression bug made popwin unopenable when in systray 2012-03-28 12:11 henriwww * ChangeLog, Nagstamon/GUI.py, installer/debian/changelog: regression bug of vanishing windows statusbar maybe fixed 2012-03-28 10:29 henriwww * Nagstamon/GUI.py: once again a stupid Windows workaround 2012-03-28 06:41 henriwww * Nagstamon/GUI.py, installer/windows/nagstamon.iss: adjusted heightbuffer 2012-03-27 13:06 henriwww * Nagstamon/Actions.py: kind of fixed popwin misplacement part II 2012-03-27 10:19 henriwww * Nagstamon/GUI.py: kind of fixed popwin misplacement 2012-03-26 13:27 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py: solution for non-showing popwin seems near 2012-03-23 16:28 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py: one step further to fix that GUI glitches of popwin when statusbar is on bottom of screen 2012-03-22 11:38 henriwww * ChangeLog: release candidate preparation 2012-03-22 11:28 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py: some cleaning 2012-03-22 10:28 henriwww * Nagstamon/GUI.py: fix for last fix 2012-03-21 14:13 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py: fixed popwin resize trouble in windows 2012-03-21 10:11 henriwww * Nagstamon/Actions.py: reset update frequency to 60 secs 2012-03-21 10:10 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py: new attempt to fix Windows popwin resizing madness 2012-03-13 23:32 henriwww * Nagstamon/GUI.py: strange windows popwin resize bug still unsolved.... 2012-03-13 14:35 henriwww * Nagstamon/GUI.py: deleted comments 2012-03-13 14:28 henriwww * Nagstamon/GUI.py: fixed windows systray popwin trouble 2012-03-12 14:34 henriwww * Nagstamon/GUI.py: fiddling around with windows popwin artefact 2012-02-21 06:53 henriwww * Nagstamon/__init__.py: corrected FSD address in __init__:.py 2012-02-20 08:23 henriwww * Nagstamon/GUI.py, installer/windows/nagstamon.iss: next attempt to fix stealing focus 2012-02-20 07:58 henriwww * ChangeLog, Nagstamon/GUI.py, Nagstamon/Server/Generic.py: reverted last changes to rc16 2012-02-17 16:32 henriwww * Nagstamon/GUI.py: trying to fix latest focus stealing bug V 2012-02-17 16:23 henriwww * Nagstamon/GUI.py: trying to fix latest focus stealing bug IV 2012-02-17 16:17 henriwww * Nagstamon/GUI.py: trying to fix latest focus stealing bug III 2012-02-17 16:03 henriwww * Nagstamon/GUI.py: trying to fix latest focus stealing bug II 2012-02-17 16:01 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py: trying to fix latest focus stealing bug 2012-02-14 10:20 henriwww * Nagstamon/Server/Generic.py, installer/windows/nagstamon.iss: trying to fix windows beatifulsoup problem 2012-02-13 14:45 henriwww * Nagstamon/Server/Generic.py: try to fix empty status information 2012-02-13 13:48 henriwww * ChangeLog, Nagstamon/GUI.py, Nagstamon/Server/Generic.py: fighting the stolen focus of systray icon 2012-02-13 12:31 henriwww * Nagstamon/GUI.py: focus stealing fix part II 2012-02-13 11:22 henriwww * Nagstamon/GUI.py: omit raising statusbar when icon in systray 2012-02-13 09:59 henriwww * Nagstamon/GUI.py, installer/windows/nagstamon.iss: fixed misplacement of popup when in systray 2012-02-09 09:55 henriwww * Nagstamon/Actions.py: fix for sound play subprocess (print deleted) 2012-02-09 08:36 henriwww * installer/windows/nagstamon.iss: rc13 iss 2012-02-09 08:34 henriwww * Nagstamon/Actions.py: subprocess shell=true part II 2012-02-09 08:10 henriwww * Nagstamon/Actions.py: subprocess open for command actions 2012-02-08 10:44 henriwww * installer/windows/nagstamon.iss: rc12 iss 2012-02-08 10:40 henriwww * Nagstamon/GUI.py: resize overlay in Ubuntu disabled - also for popwin - fixed 2012-02-08 10:30 henriwww * Nagstamon/GUI.py: resize overlay in Ubuntu disabled - also for popwin 2012-02-08 10:15 henriwww * ChangeLog, Nagstamon/GUI.py: resize overlay in Ubuntu disabled 2012-02-07 15:22 henriwww * installer/windows/nagstamon.iss: rc11 iss 2012-02-07 15:07 henriwww * Nagstamon/GUI.py: test statusbar moving without artefacts for MacOSX 2012-02-07 13:46 henriwww * installer/windows/nagstamon.iss: rc10 iss 2012-02-07 13:40 henriwww * Nagstamon/GUI.py: fix for centreon monitor cgi url 2012-02-07 08:36 henriwww * Nagstamon/GUI.py: fix for flickering popwin on macosx 2012-02-07 08:07 henriwww * installer/windows/nagstamon.iss: rc9 iss file 2012-02-07 07:49 henriwww * Nagstamon/Server/Centreon.py, nagstamon.py: fix in Centreon.py, changed shebang in nagstamon.py to use env (so it also runs on macos 10.5) 2012-02-06 14:33 henriwww * Nagstamon/Server/Centreon.py: fixed centreon 2.3.3 (or 2.3+) .../xml/ndo/... URL trouble 2012-02-06 14:27 henriwww * Nagstamon/Config.py, Nagstamon/Server/Centreon.py: fixed centreon 2.3.3 (or 2.3+) .../xml/ndo/... URL trouble 2012-02-03 16:07 henriwww * Nagstamon/Config.py: added default actions as examples 2 2012-02-03 16:03 henriwww * ChangeLog, Nagstamon/Config.py: added default actions as examples 2012-02-03 14:59 henriwww * installer/windows/nagstamon.iss: rc8 iss 2012-02-03 14:53 henriwww * Nagstamon/Config.py: fixed bug with legacy configfile given on command line 2012-02-03 13:55 henriwww * installer/windows/nagstamon.iss: rc7 iss file 2012-02-03 13:50 henriwww * Nagstamon/GUI.py: after some tests with popwin it works all the old way again 2012-02-03 08:18 henriwww * Nagstamon/GUI.py: reactivated former way of statusbar popup menu because it works with newer windows gtk 2.24 version part II 2012-02-03 07:59 henriwww * Nagstamon/GUI.py: reactivated former way of statusbar popup menu because it works with newer windows gtk 2.24 version 2012-02-01 15:19 henriwww * Nagstamon/GUI.py: mac trouble after install seems to be fixed 2012-02-01 15:04 henriwww * Nagstamon/GUI.py, Nagstamon/resources/authentication_dialog.ui: fixed auth dialog 2012-02-01 09:47 henriwww * Nagstamon/GUI.py, installer/windows/nagstamon.iss: leave that windows popup menu on statusbar bug alone... 2012-01-30 14:19 henriwww * ChangeLog, Nagstamon/GUI.py: fixed windows taskbar bug 2012-01-27 16:18 henriwww * Nagstamon/GUI.py: positioning fix 2012-01-27 15:55 henriwww * Nagstamon/GUI.py: fixed MacOSX popwin-popping-always-up-bug 2012-01-27 10:30 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py: fixed bug in OpenBrowser which made it not work at all 2012-01-25 15:50 henriwww * ChangeLog, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: just another fix for just another fix... 2012-01-25 15:35 henriwww * Nagstamon/GUI.py: now REALLY fixed that popup menu statusbar thing 2012-01-25 14:52 henriwww * Nagstamon/GUI.py: kind of solution for windows statusbar madness 2012-01-25 11:30 henriwww * Nagstamon/GUI.py: ...trouble with statusbar menu on windows... 2012-01-25 11:13 henriwww * Nagstamon/GUI.py: some windows statusbar menu trouble not fixed 2012-01-25 10:28 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py: fixed bug with statusbar menu and gethost() 2012-01-25 09:49 henriwww * Nagstamon/GUI.py: reorganized sstatusbar popup menu due to strange windows bug 2012-01-24 15:01 henriwww * installer/windows/nagstamon.iss: rc2 preparations.... 2012-01-24 15:00 henriwww * ChangeLog, installer/debian/changelog: rc2 preparations 2012-01-24 14:57 henriwww * Nagstamon/GUI.py, Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/submit_check_result_dialog.ui: improved keyboard usage for ack/down/submit dialogs 2012-01-23 12:25 henriwww * installer/windows/nagstamon.iss: iss file for 0.9.9 rc1 2012-01-23 10:28 henriwww * ChangeLog, Nagstamon/resources/settings_dialog.ui, installer/debian/changelog, setup.py: some cleanup to prepare 0.9.9 release 2012-01-20 14:01 henriwww * Nagstamon/resources/settings_action_dialog.ui: finetuning action dialog 2012-01-20 13:52 henriwww * Nagstamon/Config.py, nagstamon.py: finetuning config file -> dir conversion 2012-01-20 13:48 henriwww * Nagstamon/Config.py, nagstamon.py: finetuning config file -> dir conversion 2012-01-20 11:11 henriwww * Nagstamon/Actions.py, Nagstamon/Server/Multisite.py: ...and another check_mk-duration-sort-desaster fix... 2012-01-19 15:23 henriwww * Nagstamon/Actions.py, Nagstamon/Objects.py, Nagstamon/Server/Multisite.py: trying to fix check_mk last_check sorting order 2012-01-19 09:59 henriwww * Nagstamon/Actions.py, Nagstamon/Objects.py, Nagstamon/Server/Multisite.py: fixed check_mk duration sort problem 2012-01-18 15:57 henriwww * Nagstamon/Actions.py, Nagstamon/Server/Multisite.py, Nagstamon/resources/settings_action_dialog.ui: started fixing check_mk duration order problem 2012-01-18 13:45 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_action_dialog.ui: added help for actions in actions dialog 2012-01-17 14:22 henriwww * Nagstamon/Actions.py: added default comments as variables in custom actions 2012-01-17 14:09 henriwww * Nagstamon/Config.py, Nagstamon/Server/Generic.py, Nagstamon/resources/settings_action_dialog.ui, nagstamon.py: deleted som debugging stuff 2012-01-17 13:24 henriwww * Nagstamon/GUI.py: fixed dont-close-popwin-when-accessing-monitor-via-context-menu-bug 2012-01-17 13:15 henriwww * Nagstamon/GUI.py, Nagstamon/Objects.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py: fixed some multisite umlaut problem 2012-01-17 08:33 henriwww * Nagstamon/GUI.py, installer/windows/nagstamon.iss: let windows popwin menus work again 2012-01-17 06:48 henriwww * Nagstamon/GUI.py: cleaned fixed MS Windows popwin stuff 2012-01-16 15:56 henriwww * Nagstamon/GUI.py: fixed MS Windows popwin trouble with installation of pygtk aio 2.24.1 2012-01-16 13:26 henriwww * Nagstamon/GUI.py: trying to fix new popwin trouble in windows resulting from TOPLEVEL window type 2012-01-16 08:22 henriwww * Nagstamon/Actions.py, Nagstamon/Config.py, nagstamon.py: kind of fixed check_mk duration sorting bug 2012-01-13 15:23 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/resources/authentication_dialog.ui, nagstamon.py: startup password dialog works again 2012-01-13 14:29 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, nagstamon.py: auth in powin works 2012-01-12 15:29 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py: integrated auth dialog as auth line in popwin - dialogs caused crashes 2012-01-12 13:51 henriwww * Nagstamon/GUI.py, nagstamon.py: changing auth dialog into auth line in popwin... experimenting 2012-01-12 09:20 henriwww * Nagstamon/GUI.py, nagstamon.py: ...fixing resources path... 2012-01-12 08:50 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/resources/authentication_dialog.ui, Nagstamon/resources/authentification_dialog.ui: some authentication dialog cosmetics 2012-01-11 14:31 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py, nagstamon.py: nagstamon.py: Fatal IO error 0 (Erfolg) on X server :0. 2012-01-11 12:16 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/resources/settings_action_dialog.ui: trying to fix gtk/thread related segfaults 2012-01-09 14:31 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/resources/authentification_dialog.ui, nagstamon.py: fiddling with auth dialog... 2012-01-05 10:28 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/resources/authentification_dialog.ui: kind of finished authentication-trouble-password-dialog 2012-01-04 15:38 henriwww * Nagstamon/Actions.py, Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/resources/authentification_dialog.ui, Nagstamon/resources/settings_action_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui, nagstamon.py: extended ask-for-password-functionality to ask also if there are any authentication problems 2012-01-03 15:30 henriwww * Nagstamon/Actions.py, Nagstamon/Server/Generic.py: added permanent asking for password in case authentification failed 2012-01-03 14:47 henriwww * Nagstamon/Actions.py, Nagstamon/Server/Centreon.py: added error treatment for centreon 2012-01-03 14:15 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Multisite.py, Nagstamon/Server/Ninja.py, Nagstamon/resources/settings_server_dialog.ui: change settings dialog fields depending on server type - hide monitor cgi url if not needed 2012-01-03 13:09 henriwww * Nagstamon/Actions.py, Nagstamon/Objects.py: check_mk duration sorting fix 2012-01-02 15:10 henriwww * Nagstamon/Actions.py, Nagstamon/Config.py, Nagstamon/Custom.py, Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py, Nagstamon/Server/Ninja.py, Nagstamon/Server/Opsview.py, Nagstamon/Server/Pingdom.py, Nagstamon/Server/PingdomAPI.py, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui, nagstamon.py: based all button actions like history, services etc. on new Actions.Action via server method OpenBrowser - this should reduce complexity 2011-12-27 15:56 henriwww * Nagstamon/Actions.py, Nagstamon/Custom.py, Nagstamon/Objects.py, Nagstamon/Server/Pingdom.py, Nagstamon/Server/PingdomAPI.py, Nagstamon/resources/settings_dialog.ui: added first try of pingdom integration 2011-12-27 13:42 henriwww * Nagstamon/Actions.py, Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Multisite.py, nagstamon.py: maybe fixed conversion from config file to config dir 2011-12-01 19:18 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Ninja.py, Nagstamon/Server/Opsview.py: added functionality to history button for Nagios, Icinga, Opsview, Centreon and Ninja - Check_MK comes soon 2011-12-01 18:08 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/resources/history.png, Nagstamon/resources/history.svg, Nagstamon/resources/services.png, Nagstamon/resources/services.svg: added not yet working history button in server vbox 2011-12-01 16:46 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py: added option for action to choose between closing or leaving popup window open after action 2011-11-30 16:39 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Opsview.py: fixed sf.net bug 3441770 - sond not able to play without flashing statusbar 2011-11-25 17:36 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_action_dialog.ui: added close_popup_window option to actions 2011-11-22 15:04 henriwww * Nagstamon/Config.py: added more example actions+++ 2011-11-22 14:42 henriwww * Nagstamon/Config.py: added more example actions+++ 2011-11-22 14:25 henriwww * Nagstamon/Config.py: added more example actions 2011-11-22 13:23 henriwww * Nagstamon/Config.py: added default actions 2011-11-22 11:22 henriwww * Nagstamon/Config.py: fix for settings dialog 2011-11-22 11:18 henriwww * Nagstamon/GUI.py: fix for settings dialog 2011-11-22 10:27 henriwww * Nagstamon/Config.py: fix for new install 2011-11-22 09:37 henriwww * Nagstamon/Config.py: no segfault when canceling settings dialog 2011-11-22 09:29 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: convert legacy config file 2011-11-21 10:50 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: fix for mac regarding statusbar 2011-11-21 09:25 henriwww * Nagstamon/GUI.py: fixed typo 2011-11-21 09:18 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_action_dialog.ui, Nagstamon/resources/settings_dialog.ui: changed action filters to action re filters analogue to servers, added status information filters 2011-11-19 21:59 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_action_dialog.ui, Nagstamon/resources/settings_dialog.ui, nagstamon.py: fixes for custom actions gui, conversion of old settings to new custom actions 2011-11-18 15:47 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_action_dialog.ui, Nagstamon/resources/settings_dialog.ui: added gui editor for actions 2011-11-18 09:42 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.ui, Nagstamon/resources/settings_action_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui, Nagstamon/resources/submit_check_result_dialog.ui, nagstamon.py: corrected default enter key action in dialogs 2011-11-11 16:01 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_action_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui: added first prototype of at least appearing action edit dialog, some code cleaning at the server edit area 2011-11-10 22:48 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/resources/settings_action_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui: started action dialog 2011-11-07 22:12 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_action_dialog.ui, Nagstamon/resources/settings_dialog.ui: started with action gui editor 2011-11-07 14:01 henriwww * Nagstamon/Actions.py, Nagstamon/Config.py, Nagstamon/GUI.py: tuning custom actions 2011-11-02 13:34 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py: playing with host/service filters for actions, incomplete 2011-11-01 22:31 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py: playing with custom actions, adding examples and .target properties for actions 2011-11-01 14:34 henriwww * Nagstamon/Actions.py, Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py: first working version of GUI-less custom actions (edit yourself in ~/.nagstamon/actions 2011-11-01 10:16 henriwww * Nagstamon/Config.py: fixed error when config dir did not exist yet 2011-10-28 15:24 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py, Nagstamon/Server/Ninja.py: started with customizable actions, saves config files and displays on context menu 2011-10-28 14:21 henriwww * Nagstamon/Config.py: SaveMultipleConfig works 2011-10-28 13:42 henriwww * Nagstamon/Config.py: SaveMutlipleConfig added 2011-10-28 13:16 henriwww * Nagstamon/Config.py: LoadConfig() -> LoadMultipleConfig() part 2 2011-10-28 13:15 henriwww * Nagstamon/Config.py: LoadConfig() -> LoadMultipleConfig() 2011-10-28 12:43 henriwww * Nagstamon/Config.py: added actions class for config 2011-10-28 12:38 henriwww * Nagstamon/Config.py: abstract load config 2011-10-28 10:05 op5-team * Nagstamon/Config.py: Config.py, fixed so if your ~/.nagstamon dir doesn't exists it will be created If the basedir doesn't exist ./servers can't be created, and the save will fail. Sign-off: Mattias Ryrlén 2011-10-27 18:04 henriwww * Nagstamon/__init__.py, Nagstamon/resources/nagstamon.desktop: updated .desktop file and FSD address 2011-10-27 13:18 henriwww * Nagstamon/Config.py, nagstamon.py: new config dir with extra servers dir works (loads and saves) 2011-10-27 07:06 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Icinga.py: finally fixed icinga ack bug 2011-10-26 21:23 henriwww * Nagstamon/Server/Icinga.py: the Icinga workaround did not really work so it is now excluded again 2011-10-26 20:00 henriwww * Nagstamon/Server/Icinga.py: fixed trouble with Icinga acknowledging services 2011-10-26 14:57 henriwww * Nagstamon/GUI.py: ... 2011-10-26 14:35 henriwww * Nagstamon/GUI.py: server settings button removed and filter settings button on popwin added 2011-10-26 14:14 henriwww * Nagstamon/GUI.py: server settings button implemented 2011-10-26 12:28 henriwww * Nagstamon/Config.py, Nagstamon/Server/Generic.py, Nagstamon/resources/settings_dialog.ui: added filter for flapping items 2011-10-25 13:57 henriwww * installer/debian/changelog: added tag 0.9.8 2011-10-24 13:03 henriwww * installer/0install/nagstamon.xml, setup.py: release preparations 2011-10-24 12:23 henriwww * Nagstamon/GUI.py: release preparations 2011-10-24 10:27 henriwww * installer/0install/nagstamon.xml, installer/debian/changelog, installer/windows/nagstamon.iss: release preparations 2011-10-24 09:23 henriwww * ChangeLog, Nagstamon/GUI.py, installer/0install/nagstamon.xml: release preparations... 2011-10-14 15:11 henriwww * Nagstamon/resources/settings_dialog.ui: fixed last fix... 2011-10-14 15:07 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui, installer/0install/nagstamon.xml: fixed silly duration hours in spinbutton 2011-10-14 13:20 henriwww * Nagstamon/Server/Generic.py, installer/0install/nagstamon.xml: fixed trouble with persistent acknowledgements 2011-10-13 11:11 henriwww * Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui, Nagstamon/resources/submit_check_result_dialog.ui: set gtk version required to 2.20 2011-10-12 19:11 henriwww * Nagstamon/resources/settings_dialog.ui: cleaning settings_dialog.ui again from selection stuff 2011-10-11 10:00 henriwww * installer/0install/nagstamon.xml: deletet op5-dev because it is obsolete 2011-09-30 14:00 henriwww * Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py: Fixes for Centreon and changed page ids... why ever 2011-09-29 14:32 henriwww * Nagstamon/Server/Centreon.py, installer/0install/nagstamon.xml: applied patch for centreon to be authentication method agnostic 2011-09-29 13:40 henriwww * Nagstamon/GUI.py, installer/0install/nagstamon.xml: some macosx cosmetics 2011-09-29 10:18 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: workaround for sf.net bug #3389241 2011-09-28 14:29 henriwww * Nagstamon/resources/settings_dialog.ui, installer/0install/nagstamon.xml: working on fix for sf.net bug #3389241 2011-09-28 09:39 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/submit_check_result_dialog.ui, installer/0install/nagstamon.xml: added editable defaults for downtime 2011-09-27 20:56 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/settings_dialog.ui, installer/0install/nagstamon.xml: added editable defaults for acknowledgement and submit check results 2011-09-27 13:16 henriwww * Nagstamon/GUI.py: fix for acknowledge-dialog 2011-09-27 12:54 henriwww * Nagstamon/resources/settings_dialog.ui, installer/0install/nagstamon.xml: little settings ui fix 2011-09-27 08:23 henriwww * Nagstamon/resources/settings_dialog.ui: tuned ui files 2011-09-26 22:01 henriwww * Nagstamon/Config.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py, Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/settings_dialog.ui: added possibility to connect to hosts via hostname as-is in monitor without any HTML-parsing-to-get-one-IP-overhead 2011-09-26 20:47 henriwww * Nagstamon/Server/Generic.py: fixed always-sent-notifications-regardless-if-wanted-or-not bug sf.net #3304098 2011-09-26 20:06 henriwww * installer/0install/nagstamon.xml: 0install update 2011-09-26 19:47 henriwww * Nagstamon/GUI.py: ... 2011-09-26 19:41 henriwww * Nagstamon/resources/settings_dialog.ui: ... 2011-09-26 19:34 henriwww * Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui, Nagstamon/resources/submit_check_result_dialog.ui: changed dialoges to modal 2011-09-26 19:26 henriwww * Nagstamon/GUI.py: melted macosx changes 2011-09-26 19:21 henriwww * Nagstamon/GUI.py: fiddling macosx settings 2011-09-26 10:49 henriwww * installer/0install/nagstamon.xml: updated 0install 2011-09-26 09:12 henriwww * Nagstamon/GUI.py: MacOS now allows to edit settings without restarting Nagstamon 2011-09-26 08:13 henriwww * Nagstamon/GUI.py, Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.ui: fixed uneditable text entry fields in acknowledge & downtime dialog 2011-09-07 08:54 henriwww * Nagstamon/GUI.py, installer/0install/nagstamon.xml: avoid flicker and powin artefact occuring sometimes when hovering statusbar 2011-09-06 14:40 henriwww * Nagstamon/GUI.py: unsussessful attempt to get rid of popwin artefact 2011-09-05 00:08 henriwww * installer/0install/DMG_background.png, installer/0install/DMG_background.svg, installer/0install/Nagstamon.dmg: added modified DMG file 2011-09-04 23:43 henriwww * Nagstamon/GUI.py, installer/0install/DMG_background.png, installer/0install/DMG_background.svg, installer/0install/nagstamon.svg: added macosx dmg background 2011-09-02 17:11 henriwww * installer/darwin: deleting darwin stuff in favor of 0install 2011-09-02 17:10 henriwww * installer/0install/nagstamon.xml: ... 2011-09-02 15:05 op5-team * Nagstamon/Server/Ninja.py: Fixed issue where downtime hosts/services wasn't filtered out. typo _ should be -, shame on you Henri ;-) This resolves issue: 3391767 // Mattias Ryrlén 2011-09-02 14:07 op5-team * Nagstamon/Server/Ninja.py: Fixed issue where some host/services where not displaying, this was due to bad settings in how many items you will display on a page. We now override this by fetching total of 10000 items (if you have so many problems) 2011-09-02 12:12 henriwww * Nagstamon/GUI.py, installer/0install/nagstamon.xml: fixed crashing macosx version after setup 2011-09-02 10:40 henriwww * Nagstamon/GUI.py, installer/0install/nagstamon.xml, installer/0install/nagstamon_svn_430.tar.gz: more fixes for MacOSX 2011-09-01 07:09 henriwww * Nagstamon/GUI.py: delete debug code 2011-09-01 07:07 henriwww * Nagstamon/GUI.py: another attempt to keep popwin above other windows 2011-09-01 06:31 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: small fixes 2011-09-01 06:27 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py: added DummyStatusIcon class for MacOSX 2011-08-31 20:36 henriwww * Nagstamon/resources/settings_dialog.ui: settings ui regression bug fixed 2011-08-31 19:25 henriwww * installer/0install/nagstamon.png: 0install icon resized (bigger) 2011-08-31 19:09 henriwww * installer/0install/Nagstamon.xml, installer/0install/nagstamon.xml: more 0install changes 2011-08-31 18:57 henriwww * installer/0install/Nagstamon.xml, installer/0install/nagstamon.png, installer/0install/nagstamon_svn_430.tar.gz: changed 0install to nagstamon.ifw-dresden.de 2011-08-31 08:49 henriwww * Nagstamon/Server/Generic.py, Nagstamon/resources/settings_dialog.ui: macos fix 2011-08-30 14:33 henriwww * installer/0install, installer/0install/9E66F7361FBA0942.gpg, installer/0install/Nagstamon.xml, installer/0install/interface.xsl, installer/windows/nagstamon.iss: experimenting with 0install for MacOSX 2011-08-10 22:28 henriwww * Nagstamon/GUI.py, setup.py: fix for statusbar-not-overlapping-popup window dit not work 2011-08-10 21:15 henriwww * Nagstamon/GUI.py: changed comment in GUI.py 2011-08-10 21:14 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: fixed typo in settings dialog, use svg in windows 2011-08-04 05:54 henriwww * Nagstamon/resources/settings_dialog.ui: fixed typo in settings dialog 2011-08-03 13:40 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui, installer/debian/changelog: added ability to keep status detail popup open despite hovering away 2011-08-03 13:16 henriwww * Nagstamon/Actions.py, installer/debian/changelog: added version-dependent update-check for that test versions don't tell there is an older "update" 2011-08-03 13:05 henriwww * Nagstamon/GUI.py, installer/debian/changelog: keep popwin higher than statusbar 2011-08-03 12:22 henriwww * Nagstamon/Server/Opsview.py: added flapping symbol for Opsview servers 2011-07-08 09:27 henriwww * Nagstamon/Server/Centreon.py: fixed sf.net bug #3346031 - broken Centreon context menu actions 2011-07-08 08:45 henriwww * Nagstamon/Actions.py, Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/resources/settings_dialog.ui: added status information regexp filter 2011-07-07 09:26 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: after switch to GTK Builder the play buttons for custom sounds did not work anymore - fixed this with gtk.Buildable.get_name(playbutton) instead of playbutton.name. Anyway nobody seemed to notice - does it mean nobody uses this feature? 2011-07-07 08:41 henriwww * Nagstamon/Config.py, Nagstamon/resources/settings_dialog.ui: workaround for SF.net bug #3304423 2011-06-06 11:19 henriwww * Nagstamon/resources/settings_dialog.ui: kicked out lines 95-97 from Nagstamon/resources/settings_dialog.ui which seems to solve problem sf.net 3310224 2011-06-06 11:13 henriwww * Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui, Nagstamon/resources/submit_check_result_dialog.ui: last fix was no fix :-( 2011-06-06 11:06 henriwww * Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.ui, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui, Nagstamon/resources/submit_check_result_dialog.ui: trying gtk ui builder fix for sf.net bug 3310224 2011-05-30 10:11 henriwww * Nagstamon/GUI.py, installer/debian/changelog, installer/windows/nagstamon.iss, setup.py: release 0.9.7.1 preparations 2011-05-30 09:39 henriwww * Nagstamon/Server/Centreon.py: hot fix for sf.net bug 3309166 - broken centreon support 2011-05-27 15:38 henriwww * Nagstamon/resources/nagstamon.desktop: added .desktop file 2011-05-27 14:52 henriwww * ChangeLog, Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, installer/debian/changelog, installer/debian/control, setup.py: ready for realeasing 0.9.7 bugfix release 2011-05-27 12:32 henriwww * Nagstamon/GUI.py, Nagstamon/Objects.py, Nagstamon/Server/Generic.py: merged passive and disabled property of hosts/services as they are used repectively but meaning the same, in my opinion 2011-05-27 09:36 henriwww * Nagstamon/Actions.py, Nagstamon/Objects.py, Nagstamon/Server/Generic.py, setup.py: changed filtering passiveonly hosts/services to disabled hosts/services to fit with filter_hosts_services_disabled_checks 2011-05-26 09:58 henriwww * Nagstamon/Config.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Icinga.py, Nagstamon/resources/settings_dialog.ui: added filter for services on acknowledged host 2011-05-25 11:34 henriwww * Nagstamon/Actions.py, Nagstamon/Server/Generic.py: seemingly fixed https://sourceforge.net/tracker/?func=detail&atid=1101370&aid=3307344&group_id=236865 2011-05-21 20:10 henriwww * Nagstamon/GUI.py: fixed typo which rendered remote rdp connectuion unusable 2011-05-18 12:11 henriwww * Nagstamon/Server/Centreon.py: fixed Centreon Soft state bug https://sourceforge.net/tracker/index.php?func=detail&aid=3303861&group_id=236865&atid=1101370 2011-05-16 10:27 henriwww * Nagstamon/Server/Generic.py, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.ui: saved world peace (https://sourceforge.net/tracker/?func=detail&atid=1101370&aid=3302612&group_id=236865) :-) and added tag for 0.9.6.1 as well as fixes in .ui files where it was impossible to type text into textentry fields 2011-05-13 13:08 henriwww * Nagstamon/Server/Generic.py: fix for submit check result - wrong states in generic 2011-05-13 13:03 henriwww * Nagstamon/resources/submit_check_result_dialog.ui: missing dialog ui for submitting check results 2011-05-13 13:00 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Ninja.py, Nagstamon/Server/Opsview.py: submitting check results working for Nagios, Icinga, Opsview 2011-05-12 13:23 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py, Nagstamon/Server/Ninja.py, Nagstamon/Server/Opsview.py: added multisite icon detection for flapping/passive, started working on submit check result 2011-05-11 13:49 henriwww * Nagstamon/Server/Ninja.py: icon detection works for hosts on Ninja 2011-05-11 13:25 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Ninja.py: changed ninja host/service flag detection to generic tag based way 2011-05-11 12:17 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/resources/nagstamon_downtime.png, Nagstamon/resources/nagstamon_downtime.svg, Nagstamon/resources/nagstamon_passive.png, Nagstamon/resources/nagstamon_passive.svg, installer/debian/changelog: added passive_only detection 2011-05-11 06:54 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: grid is toggable 2011-05-11 06:11 henriwww * Nagstamon/GUI.py, Nagstamon/resources/nagstamon_flapping.png, Nagstamon/resources/nagstamon_flapping.svg: added grid lines in popwin 2011-05-10 13:45 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py: adjusting column color alternation difference 2011-05-10 13:24 henriwww * Nagstamon/GUI.py: added alternating column colors in overview 2011-05-10 11:37 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/resources/nagstamon_flapping.png, Nagstamon/resources/nagstamon_flapping.svg: added displaying flag on hosts even if they are not down (in service line), added flapping icon/detection 2011-05-10 09:45 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py, Nagstamon/resources/nagstamon_acknowledged.svg, installer/windows/nagstamon.iss: trying to fix https://sourceforge.net/tracker/index.php?func=detail&aid=3299790&group_id=236865&atid=1101370 2011-05-09 09:13 henriwww * Nagstamon/Server/Multisite.py: added detection of flags for services (ack/downtime) on Multisite 2011-05-08 13:14 henriwww * Nagstamon/Server/Generic.py: fixed bug that treeview in popwin got empty if connection errors occured 2011-05-06 23:03 henriwww * installer/windows/nagstamon.iss: windows ISS file for 0.9.6.1 2011-05-06 22:32 henriwww * ChangeLog: updated Changelog 2011-05-06 22:17 henriwww * installer/debian/changelog: debian changelog corrected 2011-05-06 22:10 henriwww * Nagstamon/GUI.py, setup.py: cosmetics for 0.9.6.1 2011-05-06 21:24 henriwww * Nagstamon/Server/Generic.py: fix for https://sourceforge.net/tracker/index.php?func=detail&aid=3298321&group_id=236865&atid=1101370 2011-05-06 10:02 henriwww * Nagstamon/GUI.py: another fix with sound options settings 2011-05-06 09:40 henriwww * Nagstamon/resources/settings_dialog.ui: fix in sound repeat gui settings 2011-05-06 09:05 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/resources/nagstamon_acknowledged.png, Nagstamon/resources/nagstamon_downtime.png: added repeated soundnotification, solves https://sourceforge.net/tracker/index.php?func=detail&aid=2947902&group_id=236865&atid=1101373 and https://sourceforge.net/tracker/?func=detail&atid=1101373&aid=3016972&group_id=236865 2011-05-05 14:26 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: readded alighnbox in server_vbox in popwin to keep buttons kind of normally stretched started with repeating acustical notification 2011-05-05 13:24 henriwww * Nagstamon/GUI.py: put connection status info in popwin more into center 2011-05-05 13:08 henriwww * Nagstamon/GUI.py, Nagstamon/resources/nagstamon_acknowledged.png, Nagstamon/resources/nagstamon_acknowledged.svg: small changes leading to beta4 2011-05-05 10:11 henriwww * Nagstamon/Server/Generic.py: fix for last fix 2011-05-05 10:07 henriwww * Nagstamon/Server/Generic.py: removed debug information 2011-05-05 09:52 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py: switched Windows back to PNG - sorry but seems to be SVG resistant fixed http://sourceforge.net/tracker/?func=detail&atid=1101370&aid=3280961&group_id=236865 2011-05-05 08:48 henriwww * Nagstamon/resources/nagstamon_acknowledged.png, Nagstamon/resources/nagstamon_acknowledged.svg, Nagstamon/resources/nagstamon_downtime.png, Nagstamon/resources/nagstamon_downtime.svg: new colorless indicator icons 2011-05-04 19:20 henriwww * Nagstamon/resources/nagstamon_downtime.svg: playing with svg icon 2011-05-04 13:37 henriwww * Nagstamon/GUI.py, installer/debian/control, installer/windows/nagstamon.iss, installer/windows/nagstamon_0.9.4.iss: small fixes for creating executables 2011-05-04 10:26 henriwww * installer/windows/nagstamon.iss: updated ISS file for 0.9.6 beta4 2011-05-04 10:08 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/resources/nagstamon_downtime.png, Nagstamon/resources/nagstamon_downtime.svg: fixing never-ending hosts list, introduced with fix for http://sourceforge.net/tracker/?func=detail&atid=1101370&aid=3293649&group_id=236865 2011-05-03 21:43 henriwww * Nagstamon/GUI.py, Nagstamon/resources/nagstamon_acknowledged.png, Nagstamon/resources/nagstamon_acknowledged.svg, Nagstamon/resources/nagstamon_downtime.png, Nagstamon/resources/nagstamon_downtime.svg: fixed windows trouble with flag indicator icons 2011-05-03 16:15 henriwww * Nagstamon/GUI.py, Nagstamon/Objects.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Opsview.py, Nagstamon/resources/nagstamon_acknowledged.png, Nagstamon/resources/nagstamon_acknowledged.svg, Nagstamon/resources/nagstamon_downtime.png, Nagstamon/resources/nagstamon_downtime.svg: popwin hosts/services overview now shows indicators for state (acknowledged/downtime) for Nagios/Icinga/Opsview/Ninja 2011-05-02 13:27 henriwww * Nagstamon/GUI.py, Nagstamon/Objects.py, Nagstamon/Server/Generic.py: playing with showing ack/downtime state in popwin - not working yet 2011-04-29 23:49 henriwww * Nagstamon/GUI.py: fixed crash after settings changes and not-applied-status-changes-in-popwin 2011-04-29 14:44 henriwww * installer/windows/nagstamon.iss: adjusted ISTool file 2011-04-29 14:05 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py: hopefully fixed new trouble in http://sourceforge.net/tracker/?func=detail&atid=1101370&aid=3293649&group_id=236865 2011-04-29 13:00 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py: solved problem with undraggable statusbar in windows with gtk 2.22 2011-04-28 21:34 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py: changing a little to be prepared for GNOME3 2011-04-28 21:24 henriwww * Nagstamon/GUI.py: trying and erroring with windows gtk 2.22 statusbar dragging... not really working 2011-04-28 13:33 henriwww * Nagstamon/GUI.py: fiddling with statusbar-not-draggable-in-windows-with-gtk-2.22 2011-04-28 09:33 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py, installer/debian/changelog, setup.py: testing without copy.deepcopy() to fix http://sourceforge.net/tracker/?func=detail&atid=1101370&aid=3293649&group_id=236865 2011-04-27 13:55 henriwww * Nagstamon/GUI.py: placing password dialog on center of screen 2011-04-27 13:47 henriwww * Nagstamon/GUI.py: playing wih password dialog gui 2011-04-27 13:29 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: changed display options to show only appliable on platform 2011-04-27 10:24 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py: don't load systray icons with every status change from file but keep them as pixbufs 2011-04-27 09:21 henriwww * Nagstamon/Server/Ninja.py: Ninja seems to work with op5 filters too 2011-04-26 14:37 henriwww * Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Multisite.py, Nagstamon/Server/Opsview.py: cleaned Servers from old filtering, now working Opsview, Centreon, Nagios + Icinga. In Multisite there are some informations missing, does not worke completely yet. 2011-04-26 13:07 henriwww * Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Opsview.py: centreon kind of works with op5-filters too 2011-04-26 12:10 henriwww * Nagstamon/Objects.py, Nagstamon/Server/Generic.py: started applying filter rewrite from op5-devel, Nagios + Icinga already working 2011-04-21 07:30 op5-team * Nagstamon/Config.py: Add changes to Config.py to actuallt work when running as .app under OSX 2011-04-20 14:03 henriwww * Nagstamon/Actions.py, Nagstamon/Server/Multisite.py: fixed bug in multisite integration (mea culpa) 2011-04-20 13:35 henriwww * Nagstamon/Server/Centreon.py, Nagstamon/Server/Icinga.py, Nagstamon/Server/LxmlFreeGeneric.py, Nagstamon/Server/Multisite.py, Nagstamon/Server/Nagios.py, Nagstamon/Server/Opsview.py: got finally rid of lxml 2011-04-20 13:27 henriwww * Nagstamon/Actions.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Icinga.py, Nagstamon/Server/LxmlFreeGeneric.py, Nagstamon/Server/Nagios.py, Nagstamon/Server/Opsview.py: ported everything from LxmlFreeGeneric.py to Generic.py 2011-04-20 12:47 henriwww * Nagstamon/Actions.py, Nagstamon/Objects.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Icinga.py, Nagstamon/Server/LxmlFreeGeneric.py, Nagstamon/Server/Nagios.py: purging all occurrences of lxml 2011-04-20 10:27 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Objects.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/LxmlFreeGeneric.py, Nagstamon/Server/Opsview.py: Opsview and Centreon do clumsily work with BeautifulSoup 2011-04-19 13:28 henriwww * Nagstamon/Objects.py, Nagstamon/Server/Icinga.py, Nagstamon/Server/LxmlFreeGeneric.py, Nagstamon/Server/Nagios.py, Nagstamon/Server/Opsview.py: further beautifulsoupization, finished Nagios/Icinga, now on Opsview 2011-04-19 10:34 op5-team * installer/darwin, installer/darwin/Makefile, installer/darwin/nagstamon.spec, installer/darwin/src, installer/darwin/src/COPYRIGHT, installer/darwin/src/LICENSE, installer/darwin/template, installer/darwin/template.dmg.bz2: MacBuild: Proof of concept Added files to build .dmg and .app for OSX Signed-off-by: Mattias Ryrlén 2011-04-15 13:15 henriwww * Nagstamon/Objects.py, Nagstamon/Server/Icinga.py, Nagstamon/Server/LxmlFreeGeneric.py: proof of concept for status flags of hosts/services based on beautifulsoup 2011-04-14 13:55 henriwww * Nagstamon/Server/LxmlFreeGeneric.py, Nagstamon/Server/Nagios.py: non-working lxml free test with nagios 2011-04-14 12:41 henriwww * Nagstamon/Server/LxmlFreeGeneric.py: added op5 LxmlFreeGeneric.py to trunk for playing with it 2011-04-14 12:25 henriwww * Nagstamon/BeautifulSoup.py: starting applying op5 beautifulsoup prrof of concept into trunk 2011-04-13 12:50 henriwww * Nagstamon/GUI.py: some GUI... 2011-04-13 09:13 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.ui: finetuning gtkbuilder ui stuff and colorbuttons 2011-04-13 07:26 henriwww * Nagstamon/GUI.py, Nagstamon/resources/acknowledge_dialog.glade, Nagstamon/resources/acknowledge_dialog.ui, Nagstamon/resources/downtime_dialog.glade, Nagstamon/resources/downtime_dialog.ui, Nagstamon/resources/settings_dialog.glade, Nagstamon/resources/settings_dialog.ui, Nagstamon/resources/settings_server_dialog.glade, Nagstamon/resources/settings_server_dialog.ui: port to gtkbuilder works 2011-04-13 06:53 henriwww * Nagstamon/resources/nagstamon.1: manpage patch by carl chenet 2011-04-11 13:41 henriwww * Nagstamon/GUI.py: added gtkbuilder patch from op5 branch to trunk - not working yet :-( 2011-04-08 09:38 henriwww * Nagstamon/resources/settings_server_dialog.glade: like before.. 2011-04-08 09:35 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade, Nagstamon/resources/settings_server_dialog.glade: still fixing windows setup dialog behaviour 2011-04-08 09:17 henriwww * Nagstamon/Config.py, Nagstamon/resources/settings_dialog.glade, Nagstamon/resources/settings_server_dialog.glade: trying to fix windows settings dialog misbehavior... 2011-04-08 09:05 henriwww * Nagstamon/GUI.py: added Robin Sonefors to contributors list 2011-04-08 09:04 henriwww * installer/windows/nagstamon.iss: inno setup fixes 2011-04-07 22:25 henriwww * Nagstamon/GUI.py: hopefully fixed regression bug with dissapearing statusbar... 2011-04-07 21:57 henriwww * installer/debian/control, installer/debian/copyright, installer/debian/nagstamon.desktop: some debian file fixes 2011-04-07 21:36 henriwww * Nagstamon/GUI.py: gui fix, strangely stretching statusbar in windows 2011-04-07 14:49 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py: fixed jumping statusbar in Windows 2011-04-07 13:39 henriwww * Nagstamon/GUI.py: gui fixes... 2011-04-07 13:37 henriwww * Nagstamon/GUI.py: gui fixes... 2011-04-07 13:17 henriwww * Nagstamon/GUI.py: new homepage address corrected 2011-04-07 12:35 henriwww * installer/windows/nagstamon.iss: .iss file for nagstamon 0.9.5 2011-04-07 11:35 henriwww * Nagstamon/Server/Ninja.py: added ninja.py fix from op5 r295 to trunk 2011-04-07 11:22 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py: fixed disabled-server-gets-cookies-bug 2011-04-05 12:26 henriwww * ChangeLog, Nagstamon/GUI.py, installer/debian/changelog, setup.py: release preparations 2011-04-05 09:49 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Multisite.py: Multisite finally added 2011-04-05 06:56 henriwww * Nagstamon/GUI.py: fixed last fix 2011-04-05 06:40 henriwww * Nagstamon/GUI.py: fixed color preview in windows 2011-04-04 14:12 henriwww * Nagstamon/Custom.py, Nagstamon/Server/Multisite.py: Check_MK Multisite server type added 2011-04-04 13:54 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: added reset button to color settings 2011-04-04 13:35 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: finally color picking works 2011-04-04 12:38 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: color preview funktioniert 2011-04-04 11:32 henriwww * Nagstamon/GUI.py: color preview works 2011-04-04 10:34 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: colors getting better 2011-04-04 10:18 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: colorbuttons exist without functions 2011-04-04 09:20 henriwww * Nagstamon/GUI.py: colorpicker proof of concept 2011-04-01 14:34 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: minor changes on color preview 2011-04-01 14:28 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: color preview in settings 2011-03-31 14:15 op5-team * Nagstamon/GUI.py: GUI.py: added logic so it displays the unreachable custom colors instead of hardcoded once in the host/service list 2011-03-31 13:54 op5-team * Nagstamon/GUI.py: GUI.py: and remove % (self.fontsize) in the end to make it actually work :/ 2011-03-31 13:17 op5-team * Nagstamon/GUI.py: GUI.py: Found one last place to use custom colors instead of hardcoded once, this for OK state 2011-03-31 12:34 henriwww * Nagstamon/Config.py, Nagstamon/resources/settings_dialog.glade: added config.py color defaults 2011-03-31 12:28 henriwww * Nagstamon/Config.py, Nagstamon/resources/settings_dialog.glade: added unreachable color 2011-03-31 12:27 op5-team * Nagstamon/GUI.py: GUI.py: Made the floating statusbar use the colors from Config.py/config files instead of the default colors 2011-03-31 11:44 op5-team * Nagstamon/GUI.py: 2011-03-31 11:16 henriwww * Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: next step with color changing 2011-03-31 10:33 henriwww * Nagstamon/resources/settings_dialog.glade: start color customization 2011-03-30 08:19 henriwww * Nagstamon/GUI.py: fixing last fix 2011-03-30 08:06 henriwww * Nagstamon/GUI.py: trying again to fix vanishing statusbar 2011-03-30 07:14 henriwww * Nagstamon/GUI.py: indendation fix for last fix 2011-03-30 07:13 henriwww * Nagstamon/GUI.py, Nagstamon/resources/settings_dialog.glade: fixes on GUI.py regarding popwin/popup menu inferences 2011-03-30 06:37 henriwww * Nagstamon/GUI.py: applied op5 patch for debian bug #617490 2011-03-29 14:57 henriwww * Nagstamon/Server/Generic.py: ... 2011-03-29 12:33 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Server/Ninja.py: fixed problem with popup menu and hovering over statusbar 2011-03-28 13:51 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Ninja.py: small corrections 2011-03-28 13:30 henriwww * Nagstamon/Server/Generic.py, Nagstamon/Server/Ninja.py: integrated Ninja 2011-03-28 13:01 henriwww * Nagstamon/Objects.py, Nagstamon/Server/Ninja.py: optimized _set_recheck in ninja 2011-03-28 12:43 henriwww * Nagstamon/Server/Ninja.py: more Ninja integration 2011-03-28 10:29 henriwww * Nagstamon/Server/Ninja.py: bringing ninja and cookies together 2011-03-28 10:13 henriwww * Nagstamon/Server/Ninja.py: ... 2011-03-28 10:10 henriwww * Nagstamon/Actions.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Ninja.py: integrating ninja 2011-03-27 11:45 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py: Icinga 1.2 acknowledgement trouble investigated, added debug to FetchURL() 2011-03-25 14:43 henriwww * Nagstamon/Server/Ninja.py: converted indents 2011-03-25 14:25 henriwww * Nagstamon/Custom.py, Nagstamon/GUI.py, Nagstamon/Server/Ninja.py: added Ninja.py from op5-dev branch, typos fixed 2011-03-25 14:08 henriwww * Nagstamon/GUI.py: os.sep insted of / - applied patch from op5-dev 2011-03-25 13:31 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Opsview.py: seemingly solved icinga acknowledgement problems, smaller fixes 2011-03-24 14:56 henriwww * Nagstamon/Server/Generic.py: fixed Icinga 1.2-1.3 compatibilty bugs 2011-03-24 13:30 henriwww * Nagstamon/Server/Generic.py: fixed missing status information when tagged 2011-03-23 15:02 henriwww * Nagstamon/GUI.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Opsview.py: fixed opsview GetHost() troble, working on Icinga-not-shown-status-information-when-link 2011-01-07 07:27 henriwww * Nagstamon/Objects.py, Nagstamon/Server/Generic.py: next version of get-passive-service-mechanism by thomas_gelf 2011-01-05 14:26 henriwww * Nagstamon/Server/Generic.py: more adjustment for passive checks... 2011-01-05 13:59 henriwww * Nagstamon/Server/Generic.py: simplified check for passive check 2011-01-05 13:33 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, Nagstamon/Objects.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py: applied and modified patch from thomas_gelf regarding passive checks - still testing 2011-01-05 08:29 henriwww * Nagstamon/Server/Centreon.py: testing Centreon with HTTP Auth 2010-12-22 14:40 henriwww * installer/windows/nagstamon.iss: added current nagstamon.iss file for automated ISS build 2010-12-22 10:45 henriwww * Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py: add some backward compatibility for python 2.4 installations like centos 5.x 2010-12-22 10:06 henriwww * Nagstamon/Actions.py, Nagstamon/GUI.py, installer/debian/changelog, setup.py: minor changes, alternatively use md5 instead hashlib on older python installations 2010-12-21 23:02 henriwww * installer/debian/rules, setup.py: modified setup.py and debian rules to work with reorganized files 2010-12-15 14:56 henriwww * Nagstamon/GUI.py: tried fixing Windows path problems 2010-12-13 09:54 henriwww * installer/debian/control, installer/debian/nagstamon.desktop: changed debian files 2010-12-13 09:31 henriwww * Nagstamon/GUI.py, setup.py: small modifications 2010-12-13 08:08 henriwww * nagstamon, nagstamon.py: rename nagstamon script to nagstamon.py 2010-12-13 07:47 henriwww * Nagstamon/Actions.py, Nagstamon/Custom.py, Nagstamon/GUI.py, Nagstamon/Objects.py, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Icinga.py, Nagstamon/Server/Nagios.py, Nagstamon/Server/Opsview.py, Nagstamon/Server/__init__.py, Nagstamon/__init__.py, nagstamon, setup.py: modified setupy.py 2010-12-13 07:07 henriwww * Nagstamon/Custom.py, Nagstamon/custom.py: 2010-12-13 07:06 henriwww * Nagstamon/nagstamonServer: reorganization 2010-12-13 07:04 henriwww * Nagstamon/Actions.py, Nagstamon/Config.py, Nagstamon/GUI.py, Nagstamon/Objects.py, Nagstamon/Server, Nagstamon/Server/Centreon.py, Nagstamon/Server/Generic.py, Nagstamon/Server/Icinga.py, Nagstamon/Server/Nagios.py, Nagstamon/Server/Opsview.py, Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonConfig.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/__init__.py: partly reorganization of modules 2010-12-10 14:02 henriwww * Nagstamon/custom.py, Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Icinga.py, Nagstamon/nagstamonServer/Nagios.py, Nagstamon/nagstamonServer/Opsview.py, installer/debian/changelog, setup.py: fixed import directives, now .deb builds again correctly 2010-12-09 14:17 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Opsview.py: Opsview works, flashing statusbar too 2010-12-08 13:06 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Icinga.py, Nagstamon/nagstamonServer/Nagios.py, Nagstamon/nagstamonServer/Opsview.py: Opsview working again 2010-12-07 16:00 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Icinga.py, Nagstamon/nagstamonServer/Nagios.py, Nagstamon/nagstamonServer/Opsview.py: workaround for not-working-basic-authentication for Nagios and Icinga servers 2010-12-01 10:10 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Opsview.py: cleaned code from debugging stuff and commented code 2010-11-26 21:45 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: cleaned unused code parts, had been mainly commented out because of testing for alternatives respectively 2010-11-26 15:10 henriwww * Nagstamon/nagstamonGUI.py: ... 2010-11-26 15:01 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: kind of progress, not generating treeview elements new with every refresh cycle but use bound object attributes instead - *seems* to work 2010-11-26 10:09 henriwww * Nagstamon/nagstamonServer/Centreon.py: ... 2010-11-26 10:02 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonServer/Centreon.py: ... 2010-11-26 09:51 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: still not really usable 2010-11-24 15:25 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: reorganized FetchURL, now way less memory consuming, still working on Treeview leak 2010-11-22 22:55 henriwww * Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: things getting worse but on their way... 2010-11-22 15:12 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: coming closer to memory leak, hides in nagstamonGUI.RefreshDisplayStatus() - completely unusable release, do not use!!! 2010-11-19 14:44 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: trying Centreon with mechanize instead of urllib2 - still leaking memory :-( mechanize is not in svn so this version will not run without adding it manually 2010-11-18 15:35 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: hunting memory leak, do not use - only works with centreon 2010-11-16 14:24 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: Testing Elementtree 2010-11-16 14:01 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py: use ElementTree instead of lxml for Centreon and it looks somehow better 2010-11-16 12:15 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Opsview.py: kind of a running gag... looking for memory leak, trying this time with ElementTree 2010-11-15 14:23 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Generic.py: seeking memory leak... :-( 2010-11-12 15:21 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: still searching for linux lxml memory leak... 2010-11-12 08:28 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py: in quest for memory leak... 2010-11-11 10:44 henriwww * Nagstamon/nagstamonGUI.py: small fixes for windows compatibility 2010-11-11 10:34 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py: small settings fix 2010-11-10 16:59 henriwww * Nagstamon/nagstamonActions.py: fixed double debug log entries 2010-11-10 16:49 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Generic.py: 2010-11-10 15:00 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Generic.py: debugging mostly works, logging debug into file (log awaited) too 2010-11-09 14:42 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonConfig.py, Nagstamon/nagstamonGUI.py, Nagstamon/resources/settings_dialog.glade: working on debug log file 2010-11-09 10:35 henriwww * Nagstamon/nagstamonConfig.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Opsview.py, Nagstamon/resources/settings_dialog.glade: centralized debugging is complete, now go on to add option to log to file 2010-11-08 22:06 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: most of centralized Debug() done 2010-11-08 15:05 henriwww * Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py: acknowledging in icinga works again, acknowledging of all services on hosts works again, reintegrated monitors submenu into statusbar context menu, started centralized debugging 2010-11-05 14:30 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Opsview.py: shows error descriptions in popup window status lines, reworked return result objects do work 2010-11-05 09:04 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Opsview.py: changed getstatus returns to objects with included error message 2010-11-04 14:49 henriwww * Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Icinga.py, Nagstamon/nagstamonServer/Opsview.py: still reworking error code, rather unstable 2010-11-03 14:47 henriwww * Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer/Generic.py: started reorganization for errors - DOES NOT WORK 2010-10-29 13:42 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Opsview.py: extended error messages, Centreon not working - don't use it! 2010-10-28 13:56 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Opsview.py, Nagstamon/nagstamonServer/__init__.py: extended error information, partly broken GUI 2010-10-27 21:43 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonServer/Generic.py: began introducing error descriptions 2010-10-27 21:07 henriwww * Nagstamon/custom.py: custom.py was missing, here we go 2010-10-27 21:06 henriwww * Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Nagios.py, Nagstamon/nagstamonServer/Opsview.py: fixed splitted server objects, USABLE again 2010-10-27 14:33 henriwww * Nagstamon/__init__.py, Nagstamon/custom.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/nagstamonServer, Nagstamon/nagstamonServer/Centreon.py, Nagstamon/nagstamonServer/Generic.py, Nagstamon/nagstamonServer/Icinga.py, Nagstamon/nagstamonServer/Nagios.py, Nagstamon/nagstamonServer/Opsview.py, Nagstamon/nagstamonServer/__init__.py: began restructuring of nagstamonObjects.py and putting servers into extra files - BROKEN, don't use it! (better fix it :-)) 2010-10-27 13:01 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py: Icinga host refresh should finally work, helping Centreon not loosing its Session ID via requesting a new one every 15 minutes 2010-10-27 06:55 henriwww * Nagstamon/nagstamonObjects.py: another icinga host recheck fix 2010-10-26 21:08 henriwww * Nagstamon/nagstamonObjects.py: kind of fixed Icinga recheck behaviour - should work, at least does with classic.demo.icinga.org 2010-10-26 19:33 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonObjects.py: macos partly failed 2010-10-26 07:22 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonConfig.py: icinga works completely 2010-10-26 05:29 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonConfig.py: testing mac bundle-ability 2010-10-25 22:17 henriwww * Nagstamon/nagstamonObjects.py: fixed Icinga+Nagios context menu non-responsiveness 2010-10-25 06:43 henriwww * Nagstamon/nagstamonGUI.py: seems to work stable with centreon 2010-10-22 13:46 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py: Centreon GetHost() for executables for services like SSH now works 2010-10-21 22:55 henriwww * Nagstamon/nagstamonObjects.py: 2010-10-21 22:07 henriwww * Nagstamon/nagstamonObjects.py: finally Centreon downtime for hosts and services works 2010-10-21 13:30 henriwww * Nagstamon/nagstamonObjects.py: downtime works for hosts in Centreon, partly/sometimes for services too 2010-10-21 07:24 henriwww * Nagstamon/nagstamonObjects.py: finally service on Icinga can be downtimed again - the cgi request has to have its arguments in the correct order, not necessary with hosts but services - why on earth? 2010-10-20 14:31 henriwww * Nagstamon/nagstamonObjects.py: Icinga monitor link works again, still suffering non-working service downtime dialog... 2010-10-20 12:43 henriwww * Nagstamon/nagstamonObjects.py: fixed broken Nagios/Icinga monitor link from context menu 2010-10-19 21:24 henriwww * Nagstamon/nagstamonObjects.py: things are getting worse... maybe an Icinga bug? 2010-10-19 14:31 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: Icinga downtiming of services des not work 2010-10-18 13:52 henriwww * Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: downtime in icinga works 2010-10-18 10:51 henriwww * Nagstamon/nagstamonObjects.py: corrected Centreon acknowledgement for services 2010-10-18 08:52 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py: fixed duration sort order bug 2010-10-15 12:45 henriwww * Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: got Centreon more stable, will get a new session id if it lost a valid one 2010-10-14 14:47 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: kind of fixed lost Centreon session ID/cookie, fix for sortable duration in popup window - not complete 2010-10-13 21:03 henriwww * Nagstamon/nagstamonObjects.py: working on centreon-losing-sessions 2010-10-07 23:13 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: working on Centreon recheck, some problem with cookies, added contributors to about dialog 2010-10-07 21:20 henriwww * Nagstamon/nagstamonObjects.py: fixed downtime getting start_time end_time due tue html changes 2010-10-07 21:11 henriwww * Nagstamon/nagstamonObjects.py: Icinga works again (with new Icinga 1.2) 2010-10-07 14:52 henriwww * Nagstamon/nagstamonObjects.py: still broken Icinga 2010-10-06 16:10 henriwww * Nagstamon/nagstamonObjects.py: working on parser for new Icinga 1.2 2010-10-06 13:06 henriwww * Nagstamon/nagstamonObjects.py: better Centreon recheck of services and hosts 2010-10-05 15:36 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py: patch for server non-stored password 2010-10-05 13:29 henriwww * Nagstamon/custom.py, Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py: Centreon rechecks for hosts and services SHOULD work - would be nice to know if they really DO... 2010-10-05 07:29 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonConfig.py, Nagstamon/nagstamonGUI.py, Nagstamon/resources/settings_server_dialog.glade: added patch from Patrick Cernko https://sourceforge.net/tracker/index.php?func=detail&aid=3081306&group_id=236865&atid=1101372 2010-10-04 13:31 henriwww * Nagstamon/nagstamonObjects.py: working on rechecking centreon hosts 2010-10-01 14:35 mrzeszut * Nagstamon/nagstamonGUI.py: fixed error with more than one click on header, still some issues with clicking while table is not fully refreshed 2010-10-01 14:10 henriwww * Nagstamon/nagstamonObjects.py: started recheck for centreon servers 2010-10-01 13:06 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py, Nagstamon/resources/acknowledge_dialog.glade: centreon host/service acknowledgement *mosttly* works 2010-10-01 10:53 mrzeszut * Nagstamon/nagstamonGUI.py: another fix for rows-reordered event (explicitely invoking method at first click, and connecting every next click) 2010-10-01 10:30 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: reworked acknowldegement 2010-10-01 10:21 mrzeszut * Nagstamon/nagstamonGUI.py: quick fix for bug or race condition with rows-reoredered event 2010-10-01 09:17 henriwww * Nagstamon/nagstamonObjects.py: Centreon acknowledging of services works 2010-09-30 17:11 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py: centreon host acknowledgement working 2010-09-27 21:14 henriwww * Nagstamon/nagstamonObjects.py: centreon filters work 2010-09-27 12:57 henriwww * Nagstamon/nagstamonObjects.py: centreon native partly working 2010-09-27 12:56 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py: centreon hosts and services shown, acknowledged-filter working 2010-09-27 09:24 henriwww * Nagstamon/nagstamonObjects.py: centreon hosts status works 2010-09-24 13:51 henriwww * Nagstamon/nagstamonObjects.py: native centreon read-only-via-xml-request WORKS (at least for services) 2010-09-23 17:32 henriwww * Nagstamon/nagstamonObjects.py: progress with XML requests to Centreon server 2010-09-22 14:13 henriwww * Nagstamon/nagstamonObjects.py: searching for memory leak and centreon ajax xml php 2010-09-21 13:35 henriwww * Nagstamon/nagstamonObjects.py: 2010-09-21 13:33 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py: broken Centreon web interface evaluation 2010-09-21 09:51 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: changes for better Centreon connectivity 2010-09-21 07:35 henriwww * Nagstamon/nagstamonObjects.py: finished better Opsview interface integration 2010-09-20 13:50 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonObjects.py, Nagstamon/resources/nagstamon.icns: working on better Opsview integration 2010-09-20 13:00 henriwww * Nagstamon/nagstamonGUI.py: fix for MacOSX SVG/PNG icon 2010-09-20 12:17 henriwww * Nagstamon/nagstamonObjects.py: fix for rechecking icinga 2010-09-20 12:01 henriwww * Nagstamon/nagstamonObjects.py: use Icinga changes from gadu-gadu-dev branch r118 2010-09-20 10:17 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: added fixes to connect to Icinga 1.0.3 servers 2010-09-16 14:10 mrzeszut * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: list of available servers in config dialog sorted by order of registering 2010-09-14 10:06 mrzeszut * Nagstamon, Nagstamon/__init__.py, Nagstamon/custom.py, Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonConfig.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/resources, Nagstamon/resources/settings_server_dialog.glade, installer/debian/changelog, installer/debian/nagstamon.desktop: merge r72:95 from gadu-gadu-rc branch possibility of custom server implementation 2010-08-27 21:36 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py: still patching memory leak 2010-08-27 20:53 henriwww * Nagstamon/nagstamonObjects.py: working on memory leak 2010-08-27 19:06 henriwww * Nagstamon/nagstamonGUI.py: fixed fix: keep toplevel-window-ified statusbar on all desktops/workspaces 2010-08-27 14:09 henriwww * Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonConfig.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: working on memory leak, this version uses shorter update interval to provoke memory leak 2010-08-27 08:50 henriwww * Nagstamon/nagstamonGUI.py: fixed Debian bug 591875 2010-08-18 12:33 henriwww * Nagstamon/nagstamonGUI.py: still fiddling with nagstamon-gets-overlapped-bug 2010-08-18 06:43 henriwww * Nagstamon/nagstamonGUI.py: removed .present() from statusbar as it steals focus from other windows 2010-08-18 05:50 henriwww * Nagstamon/nagstamonGUI.py: small fix for set_keep_above 2010-08-16 07:02 henriwww * Nagstamon/nagstamonGUI.py, installer/debian/changelog: little fix for http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591875 2010-08-10 12:25 henriwww * Nagstamon/nagstamonActions.py, Nagstamon/nagstamonGUI.py: fixed fix for feature request #3017044 2010-08-10 09:06 henriwww * Nagstamon/nagstamonActions.py: applied feature request #3017044: shorter error messages 2010-08-10 05:55 henriwww * setup.py: added Ubuntu to supported dists in build.py 2010-08-09 21:42 henriwww * Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: additional fixes for Debian bug #591875 2010-08-09 21:27 henriwww * Nagstamon/nagstamonObjects.py: fixed AttributeError: 'NagiosServer' object has no attribute 'nagitems_filtered' 2010-08-09 21:18 henriwww * Nagstamon/nagstamonGUI.py: playing with gtk window type to cure debian bug #591875 - drawback is that floating status bar cannot be put EVERYWHERE 2010-07-09 09:02 mrzeszut * Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py: merged changes from gadu-gadu-rc branch r63:71 2010-07-08 14:17 mrzeszut * installer/debian/DEBIAN, installer/debian/README.source, installer/debian/changelog, installer/debian/compat, installer/debian/control, installer/debian/copyright, installer/debian/etc, installer/debian/install, installer/debian/nagstamon.desktop, installer/debian/patches, installer/debian/patches/default_search, installer/debian/patches/series, installer/debian/rules, installer/debian/source, installer/debian/source/format, installer/debian/usr, installer/debian/watch: content of debian directory replaced by files usable by debhelpers 2010-07-08 13:40 henriwww * installer/debian/DEBIAN, installer/debian/DEBIAN/control, installer/debian/etc, installer/debian/etc/xdg, installer/debian/etc/xdg/autostart, installer/debian/etc/xdg/autostart/nagstamon.desktop, installer/debian/usr, installer/debian/usr/bin, installer/debian/usr/bin/nagstamon, installer/debian/usr/lib, installer/debian/usr/lib/nagstamon, installer/debian/usr/lib/nagstamon/__init__.py, installer/debian/usr/lib/nagstamon/nagstamon, installer/debian/usr/lib/nagstamon/nagstamonActions.py, installer/debian/usr/lib/nagstamon/nagstamonConfig.py, installer/debian/usr/lib/nagstamon/nagstamonGUI.py, installer/debian/usr/lib/nagstamon/nagstamonObjects.py, installer/debian/usr/lib/nagstamon/resources, installer/debian/usr/lib/nagstamon/resources/LICENSE, installer/debian/usr/lib/nagstamon/resources/acknowledge_dialog.glade, installer/debian/usr/lib/nagstamon/resources/close.png, installer/debian/usr/lib/nagstamon/resources/close.svg, installer/debian/usr/lib/nagstamon/resources/critical.wav, installer/debian/usr/lib/nagstamon/resources/downtime_dialog.glade, installer/debian/usr/lib/nagstamon/resources/hostdown.wav, installer/debian/usr/lib/nagstamon/resources/hosts.png, installer/debian/usr/lib/nagstamon/resources/hosts.svg, installer/debian/usr/lib/nagstamon/resources/nagios.png, installer/debian/usr/lib/nagstamon/resources/nagios.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon.ico, installer/debian/usr/lib/nagstamon/resources/nagstamon.png, installer/debian/usr/lib/nagstamon/resources/nagstamon.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_black.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_black.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_darkred.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_darkred.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_error.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_error.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_green.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_green.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_label.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_label.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_orange.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_orange.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_red.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_red.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_small.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_small.svg, installer/debian/usr/lib/nagstamon/resources/nagstamon_yellow.png, installer/debian/usr/lib/nagstamon/resources/nagstamon_yellow.svg, installer/debian/usr/lib/nagstamon/resources/recheckall.png, installer/debian/usr/lib/nagstamon/resources/recheckall.svg, installer/debian/usr/lib/nagstamon/resources/refresh.png, installer/debian/usr/lib/nagstamon/resources/refresh.svg, installer/debian/usr/lib/nagstamon/resources/services.png, installer/debian/usr/lib/nagstamon/resources/services.svg, installer/debian/usr/lib/nagstamon/resources/settings.png, installer/debian/usr/lib/nagstamon/resources/settings.svg, installer/debian/usr/lib/nagstamon/resources/settings_dialog.glade, installer/debian/usr/lib/nagstamon/resources/settings_server_dialog.glade, installer/debian/usr/lib/nagstamon/resources/warning.wav, installer/debian/usr/share, installer/debian/usr/share/applications, installer/debian/usr/share/applications/nagstamon.desktop, installer/debian/usr/share/doc, installer/debian/usr/share/doc/nagstamon, installer/debian/usr/share/doc/nagstamon/LICENSE, installer/debian/usr/share/man, installer/debian/usr/share/man/man1, installer/debian/usr/share/man/man1/nagstamon.1.gz: added debian package files 2010-07-08 13:37 henriwww * installer/debian: empty debian folder 2010-07-08 13:35 henriwww * installer/windows, installer/windows/nagstamon_0.9.4.iss: added windows installer file 2010-07-08 13:17 henriwww * installer: installer folder added 2010-06-30 10:57 mrzeszut * COPYRIGHT, ChangeLog, LICENSE, Nagstamon, Nagstamon/__init__.py, Nagstamon/nagstamon, Nagstamon/nagstamonActions.py, Nagstamon/nagstamonConfig.py, Nagstamon/nagstamonGUI.py, Nagstamon/nagstamonObjects.py, Nagstamon/resources, __init__.py, nagstamon, nagstamonActions.py, nagstamonConfig.py, nagstamonGUI.py, nagstamonObjects.py, resources, setup.py: changed structure of directories trunk, branches and tags in root directory. Each of them contains directory for single application (only Nagstamon for now). 2010-06-24 13:10 henriwww * .: Move Nagstamon into trunk 2010-06-14 14:08 henriwww * worked on non-crashing-with-pango-assertion error message 2010-06-14 08:27 henriwww * thrown gtk thread stuff away, fixed pango crash (hopefully) 2010-06-11 15:11 henriwww * more GTK thread fixes 2010-06-11 14:46 henriwww * got gtk and threads work better with windows 2010-06-11 12:41 henriwww * fixed bug in centreon code, hopefully fixed pango thread desaster 2010-06-09 14:15 henriwww * Centreon patch from Benoit Soenen added and modified - not working with demo.centreon.com - anybody likes to test? 2010-06-09 09:15 henriwww * added patch from mrdanwallis to get Nagios 1.x compatibility 2010-05-09 21:32 henriwww * fixed bug 2998035 2010-04-26 12:10 henriwww * use ungzipped manpage 2010-04-26 11:36 henriwww * 0.9.3 rc2 2010-04-23 13:24 henriwww * 0.9.3 rc1 2010-04-22 12:25 henriwww * recheck all button working 2010-04-21 13:28 henriwww * recheck all button almost working 2010-04-21 08:36 henriwww * fixed bug in update interval, added URL-IP-detection as asked in Bug 2967416 2010-04-21 08:05 henriwww * added http digest handler patch from Anonymous (https://sourceforge.net/tracker/index.php?func=detail&aid=2988938&group_id=236865&atid=1101370) 2010-04-16 14:08 henriwww * fixed problems with update interval 2010-04-09 14:39 henriwww * toggable notifications 2010-04-01 10:22 henriwww * toggle notifications working 2010-04-01 09:20 henriwww * 2010-03-31 12:55 henriwww * Opsview fully supported in context menu 2010-03-30 21:19 henriwww * experimenting with MultipartPostHandler.py 2010-03-30 14:44 henriwww * working on opsview downtime, recheck and acknowledge already work 2010-03-30 11:55 henriwww * connecting to failing hosts works in Opsview 2010-03-25 18:16 henriwww * opsview filters working 2010-03-25 15:45 henriwww * Opsview support partly working 2010-03-24 14:58 henriwww * startet work on Opsview support 2010-02-25 14:32 henriwww * fixed Mandriva bug 2010-02-19 22:09 henriwww * 2010-02-19 22:03 henriwww * added ability to filter out services on hosts in maintenance 2010-02-19 15:40 henriwww * fixed non-starting when config file is missing 2010-02-16 15:32 henriwww * various bugfixes around acknowledging, addes ability to acknowlesge all services on a host at once 2010-02-15 21:54 henriwww * finetuning enabling/disabling nagios servers 2010-02-15 15:04 henriwww * added ability to enable/disable Nagios servers 2010-02-15 10:25 henriwww * fixed bug 2950616 - Diese und die folgenden Zeilen werden ignoriert -- M Nagstamon/nagstamonActions.py M Nagstamon/resources/acknowledge_dialog.glade 2010-02-04 16:40 henriwww * looked at some GUI lag when bad connection and sometimes servers not getting restored after connection comes back - not fully usable 2010-02-02 21:40 henriwww * server status in popup window fixed 2010-02-02 14:47 henriwww * fixed bug in settings dialog with default server, fixed missing filters at start, added server connection status in popup window 2010-02-01 14:17 henriwww * use nagstamon instead of nagstamon.py, fixed bug with update interval in settings dialog 2010-01-27 15:39 henriwww * bugfixes 2010-01-27 09:46 henriwww * fixed bug with proxy users 2010-01-26 23:50 henriwww * fixed proxy settings dialog 2010-01-26 15:01 henriwww * tuning of proxy options in settings dialog, not yet complete 2010-01-26 11:06 henriwww * regexp works, some bugfixes 2010-01-25 16:05 henriwww * startet work on regexp, reworked filterung + notification 2010-01-24 10:53 henriwww * fixed settings dialog maximize button bug reported in bug 2937572 2010-01-23 00:03 henriwww * finally fixed dualscreen bugs in Windows, minor changes 2010-01-22 16:17 henriwww * some multi monitor fixes, not usable yet 2010-01-21 14:36 henriwww * show status window even on windows on dualscreen correctly 2010-01-20 09:09 henriwww * added possibility to show status popup as notification 2010-01-19 15:09 henriwww * fixed statusbar icon and systray icon statusbar placement bug 2010-01-18 15:11 henriwww * different statusbar font sizes for Windows and Unix 2010-01-18 13:47 henriwww * sound and notification working 2010-01-15 14:58 henriwww * added possibility to play sample sound files in settings dialog 2010-01-14 17:27 henriwww * working sound, notifications setting dialog 2010-01-08 14:26 henriwww * modified blinking statusbar to get some more calm 2010-01-07 19:02 henriwww * notification works for systray icon and statusbar 2010-01-06 14:26 henriwww * first attempts to implement notification 2009-12-21 16:02 henriwww * added use of proxy with username and password added automatic check for updates 2009-12-21 14:35 henriwww * 2009-12-21 14:34 henriwww * working on 0.9.0 Nagstamon-0.9.11/LICENSE000066400000000000000000000431031221401155300145310ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. Nagstamon-0.9.11/Nagstamon/000077500000000000000000000000001221401155300154525ustar00rootroot00000000000000Nagstamon-0.9.11/Nagstamon/Actions.py000077500000000000000000001271231221401155300174350ustar00rootroot00000000000000# encoding: utf-8 # Nagstamon - Nagios status monitor for your desktop # Copyright (C) 2008-2013 Henri Wahl et al. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import threading import gobject import time import datetime import urllib import webbrowser import subprocess import re import sys import traceback import gtk # if running on windows import winsound import platform if platform.system() == "Windows": import winsound # Garbage collection import gc # import for MultipartPostHandler.py which is needed for Opsview downtime form import urllib2 import mimetools, mimetypes import os, stat from Nagstamon import Objects from Nagstamon.Objects import Result #from Nagstamon import GUI import GUI # import md5 for centreon url autologin encoding try: #from python 2.5 md5 is in hashlib from hashlib import md5 except: # older pythons use md5 lib from md5 import md5 # flag which indicates if already rechecking all RecheckingAll = False def StartRefreshLoop(servers=None, output=None, conf=None): """ the everlasting refresh cycle - starts refresh cycle for every server as thread """ for server in servers.values(): if str(conf.servers[server.get_name()].enabled) == "True": server.thread = RefreshLoopOneServer(server=server, output=output, conf=conf) server.thread.start() class RefreshLoopOneServer(threading.Thread): """ one thread for one server per loop """ # kind of a stop please flag, if set to True run() should run no more stopped = False # Check flag, if set and thread recognizes do a refresh, set to True at the beginning doRefresh = True def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] # include threading mechanism threading.Thread.__init__(self, name=self.server.get_name()) self.setDaemon(1) def Stop(self): # simply sets the stopped flag to True to let the above while stop this thread when checking next self.stopped = True def Refresh(self): # simply sets the stopped flag to True to let the above while stop this thread when checking next self.doRefresh = True def run(self): """ loop until end of eternity or until server is stopped """ # do stuff like getting server version and setting some URLs self.server.init_config() while self.stopped == False: # check if we have to leave update interval sleep if self.server.count > int(self.conf.update_interval_seconds): self.doRefresh = True # self.doRefresh could also been changed by RefreshAllServers() if self.doRefresh == True: # reset server count self.server.count = 0 # check if server is already checked if self.server.isChecking == False: # set server status for status field in popwin self.server.status = "Refreshing" gobject.idle_add(self.output.popwin.UpdateStatus, self.server) # get current status server_status = self.server.GetStatus(output=self.output) # GTK/Pango does not like tag brackets < and >, so clean them out from description server_status.error = server_status.error.replace("<", "").replace(">", "").replace("\n", " ") # debug if str(self.conf.debug_mode) == "True": self.server.Debug(server=self.server.get_name(), debug="server return values: " + str(server_status.result) + " " + str(server_status.error)) if server_status.error != "": # set server status for status field in popwin self.server.status = "ERROR" # give server status description for future usage self.server.status_description = str(server_status.error) gobject.idle_add(self.output.popwin.UpdateStatus, self.server) # tell gobject to care about GUI stuff - refresh display status # use a flag to prevent all threads at once to write to statusbar label in case # of lost network connectivity - this leads to a mysterious pango crash if self.output.statusbar.isShowingError == False: gobject.idle_add(self.output.RefreshDisplayStatus) if str(self.conf.fullscreen) == "True": gobject.idle_add(self.output.popwin.RefreshFullscreen) # wait a moment time.sleep(5) # change statusbar to the following error message # show error message in statusbar # shorter error message - see https://sourceforge.net/tracker/?func=detail&aid=3017044&group_id=236865&atid=1101373 gobject.idle_add(self.output.statusbar.ShowErrorMessage, {"True":"ERROR", "False":"ERR"}[str(self.conf.long_display)]) # wait some seconds time.sleep(5) # set statusbar error message status back self.output.statusbar.isShowingError = False # wait a moment time.sleep(10) else: # set server status for status field in popwin self.server.status = "Connected" # tell gobject to care about GUI stuff - refresh display status gobject.idle_add(self.output.RefreshDisplayStatus) if str(self.conf.fullscreen) == "True": gobject.idle_add(self.output.popwin.RefreshFullscreen) # wait for the doRefresh flag to be True, if it is, do a refresh if self.doRefresh == True: if str(self.conf.debug_mode) == "True": self.server.Debug(server=self.server.get_name(), debug="Refreshing output - server is already checking: " + str(self.server.isChecking)) # reset refresh flag self.doRefresh = False # call Hook() for extra action self.server.Hook() else: # sleep and count time.sleep(1) self.server.count += 1 # call Hook() for extra action self.server.Hook() # refresh fullscreen window - maybe somehow raw approach if str(self.conf.fullscreen) == "True": gobject.idle_add(self.output.popwin.RefreshFullscreen) def RefreshAllServers(servers=None, output=None, conf=None): """ one refreshing action, starts threads, one per polled server """ for server in servers.values(): # check if server is already checked if server.isChecking == False and str(conf.servers[server.get_name()].enabled) == "True": #debug if str(conf.debug_mode) == "True": server.Debug(server=server.get_name(), debug="Checking server...") server.thread.Refresh() # set server status for status field in popwin server.status = "Refreshing" gobject.idle_add(output.popwin.UpdateStatus, server) class DebugLoop(threading.Thread): """ run and empty debug_queue into debug log file """ # stop flag stopped = False def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] # check if DebugLoop is already looping - if it does do not run another one for t in threading.enumerate(): if t.getName() == "DebugLoop": # loop gets stopped as soon as it starts - maybe waste self.stopped = True # initiate Loop try: threading.Thread.__init__(self, name="DebugLoop") self.setDaemon(1) except Exception, err: print err # open debug file if needed if str(self.conf.debug_to_file) == "True" and self.stopped == False: try: self.debug_file = open(self.conf.debug_file, "w") except Exception, err: # if path to file does not exist tell user self.output.Dialog(message=err) def run(self): # as long as debugging is wanted do it while self.stopped == False and str(self.conf.debug_mode) == "True": # .get() waits until there is something to get - needs timeout in case no debug messages fly in debug_string = "" try: debug_string = self.debug_queue.get(True, 1) print debug_string if str(self.conf.debug_to_file) == "True" and self.__dict__.has_key("debug_file") and debug_string != "": self.debug_file.write(debug_string + "\n") except: pass # if no debugging is needed anymore stop it if str(self.conf.debug_mode) == "False": self.stopped = True def Stop(self): # simply sets the stopped flag to True to let the above while stop this thread when checking next self.stopped = True class Recheck(threading.Thread): """ recheck a clicked service/host """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self, name=self.server.get_name() + "-Recheck") self.setDaemon(1) def run(self): try: self.server.set_recheck(self) except: self.server.Error(sys.exc_info()) class RecheckAll(threading.Thread): """ recheck all services/hosts """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self, name="RecheckAll") self.setDaemon(1) def run(self): # get RecheckingAll flag to decide if rechecking all is possible (only if not already running) global RecheckingAll if RecheckingAll == False: RecheckingAll = True # put all rechecking threads into one dictionary rechecks_dict = dict() try: # debug if str(self.conf.debug_mode) == "True": # workaround, take Debug method from first server reachable self.servers.values()[0].Debug(debug="Recheck all: Rechecking all services on all hosts on all servers...") for server in self.servers.values(): # only test enabled servers and only if not already if str(self.conf.servers[server.get_name()].enabled): # set server status for status field in popwin server.status = "Rechecking all started" gobject.idle_add(self.output.popwin.UpdateStatus, server) for host in server.hosts.values(): # construct an unique key which refers to rechecking thread in dictionary rechecks_dict[server.get_name() + ": " + host.get_name()] = Recheck(server=server, host=host.get_name(), service="") rechecks_dict[server.get_name() + ": " + host.get_name()].start() # debug if str(self.conf.debug_mode) == "True": server.Debug(server=server.get_name(), host=host.get_name(), debug="Rechecking...") for service in host.services.values(): # dito if service.is_passive_only() == True: continue rechecks_dict[server.get_name() + ": " + host.get_name() + ": " + service.get_name()] = Recheck(server=server, host=host.get_name(), service=service.get_name()) rechecks_dict[server.get_name() + ": " + host.get_name() + ": " + service.get_name()].start() # debug if str(self.conf.debug_mode) == "True": server.Debug(server=server.get_name(), host=host.get_name(), service=service.get_name(), debug="Rechecking...") # wait until all rechecks have been done while len(rechecks_dict) > 0: # debug if str(self.conf.debug_mode) == "True": # once again taking .Debug() from first server self.servers.values()[0].Debug(server=server.get_name(), debug="Recheck all: # of checks which still need to be done: " + str(len(rechecks_dict))) for i in rechecks_dict.copy(): # if a thread is stopped pop it out of the dictionary if rechecks_dict[i].isAlive() == False: rechecks_dict.pop(i) # wait a second time.sleep(1) # debug if str(self.conf.debug_mode) == "True": # once again taking .Debug() from first server self.servers.values()[0].Debug(server=server.get_name(), debug="Recheck all: All servers, hosts and services are rechecked.") # reset global flag RecheckingAll = False # after all and after a short delay to let the monitor apply the recheck requests refresh all to make changes visible soon time.sleep(5) RefreshAllServers(servers=self.servers, output=self.output, conf=self.conf) # do some cleanup del rechecks_dict except: RecheckingAll = False else: # debug if str(self.conf.debug_mode) == "True": # once again taking .Debug() from first server self.servers.values()[0].Debug(debug="Recheck all: Already rechecking all services on all hosts on all servers.") class Acknowledge(threading.Thread): """ exceute remote cgi command with parameters from acknowledge dialog """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self) self.setDaemon(1) def run(self): self.server.set_acknowledge(self) class Downtime(threading.Thread): """ exceute remote cgi command with parameters from acknowledge dialog """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self) self.setDaemon(1) def run(self): self.server.set_downtime(self) def Downtime_get_start_end(server, host): # get start and end time from Nagios as HTML - the objectified HTML does not contain the form elements :-( # this used to happen in GUI.action_downtime_dialog_show but for a more strict separation it better stays here return server.get_start_end(host) class SubmitCheckResult(threading.Thread): """ exceute remote cgi command with parameters from submit check result dialog """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self) self.setDaemon(1) def run(self): self.server.set_submit_check_result(self) class CheckForNewVersion(threading.Thread): """ Check for new version of nagstamon using connections of configured servers """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self) self.setDaemon(1) def run(self): """ try all servers respectively their net connections, one of them should be able to connect to nagstamon.sourceforge.net """ # debug if str(self.output.conf.debug_mode) == "True": # once again taking .Debug() from first server self.servers.values()[0].Debug(debug="Checking for new version...") for s in self.servers.values(): # if connecton of a server is not yet used do it now if s.CheckingForNewVersion == False: # set the flag to lock that connection s.CheckingForNewVersion = True # use IFW server to speed up request and secure via https result = s.FetchURL("https://nagstamon.ifw-dresden.de/files-nagstamon/latest_version_" +\ self.output.version, giveback="raw", no_auth=True) # remove newline version, error = result.result.split("\n")[0], result.error # debug if str(self.output.conf.debug_mode) == "True": # once again taking .Debug() from first server self.servers.values()[0].Debug(debug="Latest version: " + str(version)) # if we got a result notify user if error == "": if version == self.output.version: version_status = "latest" else: version_status = "out_of_date" # if we got a result reset all servers checkfornewversion flags, # notify the user and break out of the for loop for s in self.servers.values(): s.CheckingForNewVersion = False # do not tell user that the version is latest when starting up nagstamon if not (self.mode == "startup" and version_status == "latest"): # gobject.idle_add is necessary to start gtk stuff from thread gobject.idle_add(self.output.CheckForNewVersionDialog, version_status, version) break # reset the servers CheckingForNewVersion flag to allow a later check s.CheckingForNewVersion = False class PlaySound(threading.Thread): """ play notification sound in a threadified way to omit hanging gui """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self) self.setDaemon(1) def run(self): if self.sound == "WARNING": if str(self.conf.notification_default_sound) == "True": self.Play(self.Resources + "/warning.wav") else: self.Play(self.conf.notification_custom_sound_warning) elif self.sound == "CRITICAL": if str(self.conf.notification_default_sound) == "True": self.Play(self.Resources + "/critical.wav") else: self.Play(self.conf.notification_custom_sound_critical) elif self.sound == "DOWN": if str(self.conf.notification_default_sound) == "True": self.Play(self.Resources + "/hostdown.wav") else: self.Play(self.conf.notification_custom_sound_down) elif self.sound =="FILE": self.Play(self.file) def Play(self, file): """ depending on platform choose method to play sound """ # debug if str(self.conf.debug_mode) == "True": # once again taking .Debug() from first server self.servers.values()[0].Debug(debug="Playing sound: " + str(file)) if not platform.system() == "Windows": subprocess.Popen("play -q %s" % str(file), shell=True) else: winsound.PlaySound(file, winsound.SND_FILENAME) class Notification(threading.Thread): """ Flash statusbar in a threadified way to omit hanging gui """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self) self.setDaemon(1) def run(self): # counter for repeated sound soundcount = 0 # in case of notifying in statusbar do some flashing and honking while self.output.Notifying == True: # as long as flashing flag is set statusbar flashes until someone takes care if self.output.statusbar.Flashing == True: if self.output.statusbar.isShowingError == False: # check again because in the mean time this flag could have been changed by NotificationOff() gobject.idle_add(self.output.statusbar.Flash) # Ubuntu AppIndicator simulates flashing by brute force if str(self.conf.appindicator) == "True": if self.output.appindicator.Flashing == True: gobject.idle_add(self.output.appindicator.Flash) # if wanted play notification sound, if it should be repeated every minute (2*interval/0.5=interval) do so. if str(self.conf.notification_sound) == "True": if soundcount == 0: sound = PlaySound(sound=self.sound, Resources=self.Resources, conf=self.conf, servers=self.servers) sound.start() soundcount += 1 elif str(self.conf.notification_sound_repeat) == "True" and soundcount >= 2*int(self.conf.update_interval_seconds): soundcount = 0 else: soundcount += 1 time.sleep(0.5) # reset statusbar self.output.statusbar.Label.set_markup(self.output.statusbar.statusbar_labeltext) class MoveStatusbar(threading.Thread): """ Move statusbar in a threadified way to omit hanging gui and Windows-GTK 2.22 trouble """ def __init__(self, **kwds): # add all keywords to object, every mode searchs inside for its favorite arguments/keywords for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self) self.setDaemon(1) def run(self): # avoid flickering popwin while moving statusbar around # gets re-enabled from popwin.setShowable() if self.output.GUILock.has_key("Popwin"): self.output.popwin.Close() self.output.popwin.showPopwin = False # lock GUI while moving statusbar so no auth dialogs could pop up self.output.AddGUILock(self.__class__.__name__) # in case of moving statusbar do some moves while self.output.statusbar.Moving == True: gobject.idle_add(self.output.statusbar.Move) time.sleep(0.01) self.output.DeleteGUILock(self.__class__.__name__) class Action(threading.Thread): """ Execute custom actions triggered by context menu of popwin parameters are action and hosts/service """ def __init__(self, **kwds): # add all keywords to object self.host = "" self.service = "" self.status_info = "" for k in kwds: self.__dict__[k] = kwds[k] threading.Thread.__init__(self) self.setDaemon(1) def run(self): # first replace placeholder variables in string with actual values """ Possible values for variables: $HOST$ - host as in monitor $SERVICE$ - service as in monitor $MONITOR$ - monitor address - not yet clear what exactly for $MONITOR-CGI$ - monitor CGI address - not yet clear what exactly for $ADDRESS$ - address of host, investigated by Server.GetHost() $STATUS-INFO$ - status information $USERNAME$ - username on monitor $PASSWORD$ - username's password on monitor - whatever for $COMMENT-ACK$ - default acknowledge comment $COMMENT-DOWN$ - default downtime comment $COMMENT-SUBMIT$ - default submit check result comment """ try: # if run as custom action use given action definition if self.__dict__.has_key("action"): string = self.action.string action_type = self.action.type else: string = self.string action_type = self.type # mapping of variables and values mapping = { "$HOST$": self.host,\ "$SERVICE$": self.service,\ "$ADDRESS$": self.server.GetHost(self.host).result,\ "$MONITOR$": self.server.monitor_url,\ "$MONITOR-CGI$": self.server.monitor_cgi_url,\ "$STATUS-INFO$": self.status_info,\ "$USERNAME$": self.server.username,\ "$PASSWORD$": self.server.password,\ "$COMMENT-ACK$": self.conf.defaults_acknowledge_comment,\ "$COMMENT-DOWN$": self.conf.defaults_downtime_comment,\ "$COMMENT-SUBMIT$": self.conf.defaults_submit_check_result_comment, } # mapping mapping for i in mapping: string = string.replace(i, mapping[i]) # see what action to take if action_type == "browser": # make string ready for URL # should not be needed for browsers, see https://github.com/HenriWahl/Nagstamon/issues/34 ###string = self._URLify(string) # debug if str(self.conf.debug_mode) == "True": self.server.Debug(server=self.server.name, host=self.host, service=self.service, debug="ACTION: Browser " + string) webbrowser.open(string) elif self.action.type == "url": # make string ready for URL string = self._URLify(string) # debug if str(self.conf.debug_mode) == "True": self.server.Debug(server=self.server.name, host=self.host, service=self.service, debug="ACTION: URL in background " + string) self.server.FetchURL(string) elif self.action.type == "command": # debug if str(self.conf.debug_mode) == "True": self.server.Debug(server=self.server.name, host=self.host, service=self.service, debug="ACTION: COMMAND " + string) subprocess.Popen(string, shell=True) except: import traceback traceback.print_exc(file=sys.stdout) def _URLify(self, string): """ return a string that fulfills requirements for URL exclude several chars """ return urllib.quote(string, ":/=?&@") class LonesomeGarbageCollector(threading.Thread): """ do repeatedly collect some garbage - before every server thread did but might make more sense done at one place and time """ def __init__(self): # garbage collection gc.enable() threading.Thread.__init__(self) self.setDaemon(1) def run(self): while True: gc.collect() # lets do a gc.collect() once every minute time.sleep(60) def TreeViewNagios(server, host, service): # if the clicked row does not contain a service it mus be a host, # so the nagios query is different server.open_tree_view(host, service) # contains dict with available server classes # key is type of server, value is server class # used for automatic config generation # and holding this information in one place REGISTERED_SERVERS = [] def register_server(server): """ Once new server class in created, should be registered with this function for being visible in config and accessible in application. """ if server.TYPE not in [x[0] for x in REGISTERED_SERVERS]: REGISTERED_SERVERS.append((server.TYPE, server)) def get_registered_servers(): """ Returns available server classes dict """ return dict(REGISTERED_SERVERS) def get_registered_server_type_list(): """ Returns available server type name list with order of registering """ return [x[0] for x in REGISTERED_SERVERS] def CreateServer(server=None, conf=None, debug_queue=None, resources=None): # create Server from config registered_servers = get_registered_servers() if server.type not in registered_servers: print 'Server type not supported: %s' % server.type return # give argument servername so CentreonServer could use it for initializing MD5 cache nagiosserver = registered_servers[server.type](conf=conf, name=server.name) nagiosserver.type = server.type nagiosserver.monitor_url = server.monitor_url nagiosserver.monitor_cgi_url = server.monitor_cgi_url # add resources, needed for auth dialog nagiosserver.Resources = resources nagiosserver.username = server.username nagiosserver.password = server.password nagiosserver.use_autologin = server.use_autologin nagiosserver.autologin_key = server.autologin_key nagiosserver.use_proxy = server.use_proxy nagiosserver.use_proxy_from_os = server.use_proxy_from_os nagiosserver.proxy_address = server.proxy_address nagiosserver.proxy_username = server.proxy_username nagiosserver.proxy_password = server.proxy_password # if password is not to be saved ask for it at startup if ( server.enabled == "True" and server.save_password == "False" and server.use_autologin == "False" ): nagiosserver.refresh_authentication = True # access to thread-safe debug queue nagiosserver.debug_queue = debug_queue # use server-owned attributes instead of redefining them with every request nagiosserver.passman = urllib2.HTTPPasswordMgrWithDefaultRealm() nagiosserver.passman.add_password(None, server.monitor_url, server.username, server.password) nagiosserver.passman.add_password(None, server.monitor_cgi_url, server.username, server.password) nagiosserver.basic_handler = urllib2.HTTPBasicAuthHandler(nagiosserver.passman) nagiosserver.digest_handler = urllib2.HTTPDigestAuthHandler(nagiosserver.passman) nagiosserver.proxy_auth_handler = urllib2.ProxyBasicAuthHandler(nagiosserver.passman) if str(nagiosserver.use_proxy) == "False": # use empty proxyhandler nagiosserver.proxy_handler = urllib2.ProxyHandler({}) elif str(server.use_proxy_from_os) == "False": # if proxy from OS is not used there is to add a authenticated proxy handler nagiosserver.passman.add_password(None, nagiosserver.proxy_address, nagiosserver.proxy_username, nagiosserver.proxy_password) nagiosserver.proxy_handler = urllib2.ProxyHandler({"http": nagiosserver.proxy_address, "https": nagiosserver.proxy_address}) nagiosserver.proxy_auth_handler = urllib2.ProxyBasicAuthHandler(nagiosserver.passman) # create permanent urlopener for server to avoid memory leak with millions of openers nagiosserver.urlopener = BuildURLOpener(nagiosserver) # server's individual preparations for HTTP connections (for example cookie creation), version of monitor if str(server.enabled) == "True": nagiosserver.init_HTTP() # debug if str(conf.debug_mode) == "True": nagiosserver.Debug(server=server.name, debug="Created server.") return nagiosserver def not_empty(x): '''tiny helper function for BeautifulSoup in GenericServer.py to filter text elements''' return bool(x.replace(' ', '').strip()) def BuildURLOpener(server): """ if there should be no proxy used use an empty proxy_handler - only necessary in Windows, where IE proxy settings are used automatically if available In UNIX $HTTP_PROXY will be used The MultipartPostHandler is needed for submitting multipart forms from Opsview """ # trying with changed digest/basic auth order as some digest auth servers do not # seem to work wi the previous way if str(server.use_proxy) == "False": server.proxy_handler = urllib2.ProxyHandler({}) urlopener = urllib2.build_opener(server.digest_handler,\ server.basic_handler,\ server.proxy_handler,\ urllib2.HTTPCookieProcessor(server.Cookie),\ MultipartPostHandler) elif str(server.use_proxy) == "True": if str(server.use_proxy_from_os) == "True": urlopener = urllib2.build_opener(server.digest_handler,\ server.basic_handler,\ urllib2.HTTPCookieProcessor(server.Cookie),\ MultipartPostHandler) else: # if proxy from OS is not used there is to add a authenticated proxy handler server.passman.add_password(None, server.proxy_address, server.proxy_username, server.proxy_password) server.proxy_handler = urllib2.ProxyHandler({"http": server.proxy_address, "https": server.proxy_address}) server.proxy_auth_handler = urllib2.ProxyBasicAuthHandler(server.passman) urlopener = urllib2.build_opener(server.proxy_handler,\ server.proxy_auth_handler,\ server.digest_handler,\ server.basic_handler,\ urllib2.HTTPCookieProcessor(server.Cookie),\ MultipartPostHandler) return urlopener def OpenNagstamonDownload(output=None): """ Opens Nagstamon Download page after being offered by update check """ # first close popwin output.popwin.Close() # start browser with URL webbrowser.open("http://nagstamon.sourceforge.net/download") def IsFoundByRE(string, pattern, reverse): """ helper for context menu actions in context menu - hosts and services might be filtered out also useful for services and hosts and status information """ pattern = re.compile(pattern) if len(pattern.findall(string)) > 0: if str(reverse) == "True": return False else: return True else: if str(reverse) == "True": return True else: return False def HostIsFilteredOutByRE(host, conf=None): """ helper for applying RE filters in Generic.GetStatus() """ try: if str(conf.re_host_enabled) == "True": return IsFoundByRE(host, conf.re_host_pattern, conf.re_host_reverse) # if RE are disabled return True because host is not filtered return False except: import traceback traceback.print_exc(file=sys.stdout) def ServiceIsFilteredOutByRE(service, conf=None): """ helper for applying RE filters in Generic.GetStatus() """ try: if str(conf.re_service_enabled) == "True": return IsFoundByRE(service, conf.re_service_pattern, conf.re_service_reverse) # if RE are disabled return True because host is not filtered return False except: import traceback traceback.print_exc(file=sys.stdout) def StatusInformationIsFilteredOutByRE(status_information, conf=None): """ helper for applying RE filters in Generic.GetStatus() """ try: if str(conf.re_status_information_enabled) == "True": return IsFoundByRE(status_information, conf.re_status_information_pattern, conf.re_status_information_reverse) # if RE are disabled return True because host is not filtered return False except: import traceback traceback.print_exc(file=sys.stdout) def CriticalityIsFilteredOutByRE(criticality, conf=None): """ helper for applying RE filters in Generic.GetStatus() """ try: if str(conf.re_criticality_enabled) == "True": return IsFoundByRE(criticality, conf.re_criticality_pattern, conf.re_criticality_reverse) # if RE are disabled return True because host is not filtered return False except: import traceback traceback.print_exc(file=sys.stdout) def HumanReadableDuration(seconds): """ convert seconds given by Opsview to the form Nagios gives them like 70d 3h 34m 34s """ timedelta = str(datetime.timedelta(seconds=int(seconds))) try: if timedelta.find("day") == -1: hms = timedelta.split(":") if len(hms) == 1: return "0d 0h 0m %ss" % (hms[0]) elif len(hms) == 2: return "0d 0h %sm %ss" % (hms[0], hms[1]) else: return "0d %sh %sm %ss" % (hms[0], hms[1], hms[2]) else: # waste is waste - does anyone need it? days, waste, hms = str(timedelta).split(" ") hms = hms.split(":") return "%sd %sh %sm %ss" % (days, hms[0], hms[1], hms[2]) except: # in case of any error return seconds we got return seconds def HumanReadableDurationThruk(timestamp): """ Thruk server supplies timestamp of latest state change which has to be subtracted from .now() """ try: td = datetime.datetime.now() - datetime.datetime.fromtimestamp(int(timestamp)) h = td.seconds / 3600 m = td.seconds % 3600 / 60 s = td.seconds % 60 return "%sd %sh %sm %ss" % (td.days, h, m ,s) except: import traceback traceback.print_exc(file=sys.stdout) def MachineSortableDate(raw): """ Monitors gratefully show duration even in weeks and months which confuse the sorting of popup window sorting - this functions wants to fix that """ # dictionary for duration date string components d = {"M":0, "w":0, "d":0, "h":0, "m":0, "s":0} # if for some reason the value is empty/none make it compatible: 0s if raw == None: raw = "0s" # strip and replace necessary for Nagios duration values, # split components of duration into dictionary for c in raw.strip().replace(" ", " ").split(" "): number, period = c[0:-1],c[-1] d[period] = int(number) del number, period # convert collected duration data components into seconds for being comparable return 16934400 * d["M"] + 604800 * d["w"] + 86400 * d["d"] + 3600 * d["h"] + 60 * d["m"] + d["s"] def MachineSortableDateMultisite(raw): """ Multisite dates/times are so different to the others so it has to be handled separately """ # dictionary for duration date string components d = {"M":0, "d":0, "h":0, "m":0, "s":0} # if for some reason the value is empty/none make it compatible: 0 sec if raw == None: raw = "0 sec" # check_mk has different formats - if duration takes too long it changes its scheme if "-" in raw and ":" in raw: datepart, timepart = raw.split(" ") # need to convert years into months for later comparison Y, M, D = datepart.split("-") d["M"] = int(Y) * 12 + int(M) d["d"] = int(D) # time does not need to be changed h, m, s = timepart.split(":") d["h"], d["m"], d["s"] = int(h), int(m), int(s) del datepart, timepart, Y, M, D, h, m, s else: # recalculate a timedelta of the given value if "sec" in raw: d["s"] = raw.split(" ")[0] delta = datetime.datetime.now() - datetime.timedelta(seconds=int(d["s"])) elif "min" in raw: d["m"] = raw.split(" ")[0] delta = datetime.datetime.now() - datetime.timedelta(minutes=int(d["m"])) elif "hrs" in raw: d["h"] = raw.split(" ")[0] delta = datetime.datetime.now() - datetime.timedelta(hours=int(d["h"])) elif "days" in raw: d["d"] = raw.split(" ")[0] delta = datetime.datetime.now() - datetime.timedelta(days=int(d["d"])) else: delta = datetime.datetime.now() Y, M, d["d"], d["h"], d["m"], d["s"] = delta.strftime("%Y %m %d %H %M %S").split(" ") # need to convert years into months for later comparison d["M"] = int(Y) * 12 + int(M) # int-ify d for i in d: d[i] = int(d[i]) # convert collected duration data components into seconds for being comparable return 16934400 * d["M"] + 86400 * d["d"] + 3600 * d["h"] + 60 * d["m"] + d["s"] def MD5ify(string): """ makes something md5y of a given username or password for Centreon web interface access """ return md5(string).hexdigest() # # Borrowed from http://pipe.scs.fsu.edu/PostHandler/MultipartPostHandler.py # Released under LGPL # Thank you Will Holcomb! class Callable: def __init__(self, anycallable): self.__call__ = anycallable class MultipartPostHandler(urllib2.BaseHandler): handler_order = urllib2.HTTPHandler.handler_order - 10 # needs to run first def http_request(self, request): data = request.get_data() if data is not None and type(data) != str: v_vars = [] try: for(key, value) in data.items(): v_vars.append((key, value)) except TypeError: systype, value, traceback = sys.exc_info() raise TypeError, "not a valid non-string sequence or mapping object", traceback boundary, data = self.multipart_encode(v_vars) contenttype = 'multipart/form-data; boundary=%s' % boundary if(request.has_header('Content-Type') and request.get_header('Content-Type').find('multipart/form-data') != 0): print "Replacing %s with %s" % (request.get_header('content-type'), 'multipart/form-data') request.add_unredirected_header('Content-Type', contenttype) request.add_data(data) return request def multipart_encode(vars, boundary = None, buffer = None): if boundary is None: boundary = mimetools.choose_boundary() if buffer is None: buffer = '' for(key, value) in vars: buffer += '--%s\r\n' % boundary buffer += 'Content-Disposition: form-data; name="%s"' % key buffer += '\r\n\r\n' + value + '\r\n' buffer += '--%s--\r\n\r\n' % boundary return boundary, buffer multipart_encode = Callable(multipart_encode) https_request = http_request # Nagstamon-0.9.11/Nagstamon/BeautifulSoup.py000066400000000000000000002331301221401155300206150ustar00rootroot00000000000000"""Beautiful Soup Elixir and Tonic "The Screen-Scraper's Friend" http://www.crummy.com/software/BeautifulSoup/ Beautiful Soup parses a (possibly invalid) XML or HTML document into a tree representation. It provides methods and Pythonic idioms that make it easy to navigate, search, and modify the tree. A well-formed XML/HTML document yields a well-formed data structure. An ill-formed XML/HTML document yields a correspondingly ill-formed data structure. If your document is only locally well-formed, you can use this library to find and process the well-formed part of it. Beautiful Soup works with Python 2.2 and up. It has no external dependencies, but you'll have more success at converting data to UTF-8 if you also install these three packages: * chardet, for auto-detecting character encodings http://chardet.feedparser.org/ * cjkcodecs and iconv_codec, which add more encodings to the ones supported by stock Python. http://cjkpython.i18n.org/ Beautiful Soup defines classes for two main parsing strategies: * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific language that kind of looks like XML. * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid or invalid. This class has web browser-like heuristics for obtaining a sensible parse tree in the face of common HTML errors. Beautiful Soup also defines a class (UnicodeDammit) for autodetecting the encoding of an HTML or XML document, and converting it to Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser. For more than you ever wanted to know about Beautiful Soup, see the documentation: http://www.crummy.com/software/BeautifulSoup/documentation.html Here, have some legalese: Copyright (c) 2004-2010, Leonard Richardson All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. * Neither the name of the the Beautiful Soup Consortium and All Night Kosher Bakery nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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, DAMMIT. """ from __future__ import generators __author__ = "Leonard Richardson (leonardr@segfault.org)" __version__ = "3.2.0" __copyright__ = "Copyright (c) 2004-2010 Leonard Richardson" __license__ = "New-style BSD" from sgmllib import SGMLParser, SGMLParseError import codecs import markupbase import types import re import sgmllib try: from htmlentitydefs import name2codepoint except ImportError: name2codepoint = {} try: set except NameError: from sets import Set as set #These hacks make Beautiful Soup able to parse XML with namespaces sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*') markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match DEFAULT_OUTPUT_ENCODING = "utf-8" def _match_css_class(str): """Build a RE to match the given CSS class.""" return re.compile(r"(^|.*\s)%s($|\s)" % str) # First, the classes that represent markup elements. class PageElement(object): """Contains the navigational information for some part of the page (either a tag or a piece of text)""" def setup(self, parent=None, previous=None): """Sets up the initial relations between this element and other elements.""" self.parent = parent self.previous = previous self.next = None self.previousSibling = None self.nextSibling = None if self.parent and self.parent.contents: self.previousSibling = self.parent.contents[-1] self.previousSibling.nextSibling = self def replaceWith(self, replaceWith): oldParent = self.parent myIndex = self.parent.index(self) if hasattr(replaceWith, "parent")\ and replaceWith.parent is self.parent: # We're replacing this element with one of its siblings. index = replaceWith.parent.index(replaceWith) if index and index < myIndex: # Furthermore, it comes before this element. That # means that when we extract it, the index of this # element will change. myIndex = myIndex - 1 self.extract() oldParent.insert(myIndex, replaceWith) def replaceWithChildren(self): myParent = self.parent myIndex = self.parent.index(self) self.extract() reversedChildren = list(self.contents) reversedChildren.reverse() for child in reversedChildren: myParent.insert(myIndex, child) def extract(self): """Destructively rips this element out of the tree.""" if self.parent: try: del self.parent.contents[self.parent.index(self)] except ValueError: pass #Find the two elements that would be next to each other if #this element (and any children) hadn't been parsed. Connect #the two. lastChild = self._lastRecursiveChild() nextElement = lastChild.next if self.previous: self.previous.next = nextElement if nextElement: nextElement.previous = self.previous self.previous = None lastChild.next = None self.parent = None if self.previousSibling: self.previousSibling.nextSibling = self.nextSibling if self.nextSibling: self.nextSibling.previousSibling = self.previousSibling self.previousSibling = self.nextSibling = None return self def _lastRecursiveChild(self): "Finds the last element beneath this object to be parsed." lastChild = self while hasattr(lastChild, 'contents') and lastChild.contents: lastChild = lastChild.contents[-1] return lastChild def insert(self, position, newChild): if isinstance(newChild, basestring) \ and not isinstance(newChild, NavigableString): newChild = NavigableString(newChild) position = min(position, len(self.contents)) if hasattr(newChild, 'parent') and newChild.parent is not None: # We're 'inserting' an element that's already one # of this object's children. if newChild.parent is self: index = self.index(newChild) if index > position: # Furthermore we're moving it further down the # list of this object's children. That means that # when we extract this element, our target index # will jump down one. position = position - 1 newChild.extract() newChild.parent = self previousChild = None if position == 0: newChild.previousSibling = None newChild.previous = self else: previousChild = self.contents[position-1] newChild.previousSibling = previousChild newChild.previousSibling.nextSibling = newChild newChild.previous = previousChild._lastRecursiveChild() if newChild.previous: newChild.previous.next = newChild newChildsLastElement = newChild._lastRecursiveChild() if position >= len(self.contents): newChild.nextSibling = None parent = self parentsNextSibling = None while not parentsNextSibling: parentsNextSibling = parent.nextSibling parent = parent.parent if not parent: # This is the last element in the document. break if parentsNextSibling: newChildsLastElement.next = parentsNextSibling else: newChildsLastElement.next = None else: nextChild = self.contents[position] newChild.nextSibling = nextChild if newChild.nextSibling: newChild.nextSibling.previousSibling = newChild newChildsLastElement.next = nextChild if newChildsLastElement.next: newChildsLastElement.next.previous = newChildsLastElement self.contents.insert(position, newChild) def append(self, tag): """Appends the given tag to the contents of this tag.""" self.insert(len(self.contents), tag) def findNext(self, name=None, attrs={}, text=None, **kwargs): """Returns the first item that matches the given criteria and appears after this Tag in the document.""" return self._findOne(self.findAllNext, name, attrs, text, **kwargs) def findAllNext(self, name=None, attrs={}, text=None, limit=None, **kwargs): """Returns all items that match the given criteria and appear after this Tag in the document.""" return self._findAll(name, attrs, text, limit, self.nextGenerator, **kwargs) def findNextSibling(self, name=None, attrs={}, text=None, **kwargs): """Returns the closest sibling to this Tag that matches the given criteria and appears after this Tag in the document.""" return self._findOne(self.findNextSiblings, name, attrs, text, **kwargs) def findNextSiblings(self, name=None, attrs={}, text=None, limit=None, **kwargs): """Returns the siblings of this Tag that match the given criteria and appear after this Tag in the document.""" return self._findAll(name, attrs, text, limit, self.nextSiblingGenerator, **kwargs) fetchNextSiblings = findNextSiblings # Compatibility with pre-3.x def findPrevious(self, name=None, attrs={}, text=None, **kwargs): """Returns the first item that matches the given criteria and appears before this Tag in the document.""" return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs) def findAllPrevious(self, name=None, attrs={}, text=None, limit=None, **kwargs): """Returns all items that match the given criteria and appear before this Tag in the document.""" return self._findAll(name, attrs, text, limit, self.previousGenerator, **kwargs) fetchPrevious = findAllPrevious # Compatibility with pre-3.x def findPreviousSibling(self, name=None, attrs={}, text=None, **kwargs): """Returns the closest sibling to this Tag that matches the given criteria and appears before this Tag in the document.""" return self._findOne(self.findPreviousSiblings, name, attrs, text, **kwargs) def findPreviousSiblings(self, name=None, attrs={}, text=None, limit=None, **kwargs): """Returns the siblings of this Tag that match the given criteria and appear before this Tag in the document.""" return self._findAll(name, attrs, text, limit, self.previousSiblingGenerator, **kwargs) fetchPreviousSiblings = findPreviousSiblings # Compatibility with pre-3.x def findParent(self, name=None, attrs={}, **kwargs): """Returns the closest parent of this Tag that matches the given criteria.""" # NOTE: We can't use _findOne because findParents takes a different # set of arguments. r = None l = self.findParents(name, attrs, 1) if l: r = l[0] return r def findParents(self, name=None, attrs={}, limit=None, **kwargs): """Returns the parents of this Tag that match the given criteria.""" return self._findAll(name, attrs, None, limit, self.parentGenerator, **kwargs) fetchParents = findParents # Compatibility with pre-3.x #These methods do the real heavy lifting. def _findOne(self, method, name, attrs, text, **kwargs): r = None l = method(name, attrs, text, 1, **kwargs) if l: r = l[0] return r def _findAll(self, name, attrs, text, limit, generator, **kwargs): "Iterates over a generator looking for things that match." if isinstance(name, SoupStrainer): strainer = name # (Possibly) special case some findAll*(...) searches elif text is None and not limit and not attrs and not kwargs: # findAll*(True) if name is True: return [element for element in generator() if isinstance(element, Tag)] # findAll*('tag-name') elif isinstance(name, basestring): return [element for element in generator() if isinstance(element, Tag) and element.name == name] else: strainer = SoupStrainer(name, attrs, text, **kwargs) # Build a SoupStrainer else: strainer = SoupStrainer(name, attrs, text, **kwargs) results = ResultSet(strainer) g = generator() while True: try: i = g.next() except StopIteration: break if i: found = strainer.search(i) if found: results.append(found) if limit and len(results) >= limit: break return results #These Generators can be used to navigate starting from both #NavigableStrings and Tags. def nextGenerator(self): i = self while i is not None: i = i.next yield i def nextSiblingGenerator(self): i = self while i is not None: i = i.nextSibling yield i def previousGenerator(self): i = self while i is not None: i = i.previous yield i def previousSiblingGenerator(self): i = self while i is not None: i = i.previousSibling yield i def parentGenerator(self): i = self while i is not None: i = i.parent yield i # Utility methods def substituteEncoding(self, str, encoding=None): encoding = encoding or "utf-8" return str.replace("%SOUP-ENCODING%", encoding) def toEncoding(self, s, encoding=None): """Encodes an object to a string in some encoding, or to Unicode. .""" if isinstance(s, unicode): if encoding: s = s.encode(encoding) elif isinstance(s, str): if encoding: s = s.encode(encoding) else: s = unicode(s) else: if encoding: s = self.toEncoding(str(s), encoding) else: s = unicode(s) return s class NavigableString(unicode, PageElement): def __new__(cls, value): """Create a new NavigableString. When unpickling a NavigableString, this method is called with the string in DEFAULT_OUTPUT_ENCODING. That encoding needs to be passed in to the superclass's __new__ or the superclass won't know how to handle non-ASCII characters. """ if isinstance(value, unicode): return unicode.__new__(cls, value) return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING) def __getnewargs__(self): return (NavigableString.__str__(self),) def __getattr__(self, attr): """text.string gives you text. This is for backwards compatibility for Navigable*String, but for CData* it lets you get the string without the CData wrapper.""" if attr == 'string': return self else: raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr) def __unicode__(self): return str(self).decode(DEFAULT_OUTPUT_ENCODING) def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): if encoding: return self.encode(encoding) else: return self class CData(NavigableString): def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): return "" % NavigableString.__str__(self, encoding) class ProcessingInstruction(NavigableString): def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): output = self if "%SOUP-ENCODING%" in output: output = self.substituteEncoding(output, encoding) return "" % self.toEncoding(output, encoding) class Comment(NavigableString): def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): return "" % NavigableString.__str__(self, encoding) class Declaration(NavigableString): def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING): return "" % NavigableString.__str__(self, encoding) class Tag(PageElement): """Represents a found HTML tag with its attributes and contents.""" def _invert(h): "Cheap function to invert a hash." i = {} for k,v in h.items(): i[v] = k return i XML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'", "quot" : '"', "amp" : "&", "lt" : "<", "gt" : ">" } XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS) def _convertEntities(self, match): """Used in a call to re.sub to replace HTML, XML, and numeric entities with the appropriate Unicode characters. If HTML entities are being converted, any unrecognized entities are escaped.""" x = match.group(1) if self.convertHTMLEntities and x in name2codepoint: return unichr(name2codepoint[x]) elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS: if self.convertXMLEntities: return self.XML_ENTITIES_TO_SPECIAL_CHARS[x] else: return u'&%s;' % x elif len(x) > 0 and x[0] == '#': # Handle numeric entities if len(x) > 1 and x[1] == 'x': return unichr(int(x[2:], 16)) else: return unichr(int(x[1:])) elif self.escapeUnrecognizedEntities: return u'&%s;' % x else: return u'&%s;' % x def __init__(self, parser, name, attrs=None, parent=None, previous=None): "Basic constructor." # We don't actually store the parser object: that lets extracted # chunks be garbage-collected self.parserClass = parser.__class__ self.isSelfClosing = parser.isSelfClosingTag(name) self.name = name if attrs is None: attrs = [] elif isinstance(attrs, dict): attrs = attrs.items() self.attrs = attrs self.contents = [] self.setup(parent, previous) self.hidden = False self.containsSubstitutions = False self.convertHTMLEntities = parser.convertHTMLEntities self.convertXMLEntities = parser.convertXMLEntities self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities # Convert any HTML, XML, or numeric entities in the attribute values. convert = lambda(k, val): (k, re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);", self._convertEntities, val)) self.attrs = map(convert, self.attrs) def getString(self): if (len(self.contents) == 1 and isinstance(self.contents[0], NavigableString)): return self.contents[0] def setString(self, string): """Replace the contents of the tag with a string""" self.clear() self.append(string) string = property(getString, setString) def getText(self, separator=u""): if not len(self.contents): return u"" stopNode = self._lastRecursiveChild().next strings = [] current = self.contents[0] while current is not stopNode: if isinstance(current, NavigableString): strings.append(current.strip()) current = current.next return separator.join(strings) text = property(getText) def get(self, key, default=None): """Returns the value of the 'key' attribute for the tag, or the value given for 'default' if it doesn't have that attribute.""" return self._getAttrMap().get(key, default) def clear(self): """Extract all children.""" for child in self.contents[:]: child.extract() def index(self, element): for i, child in enumerate(self.contents): if child is element: return i raise ValueError("Tag.index: element not in tag") def has_key(self, key): return self._getAttrMap().has_key(key) def __getitem__(self, key): """tag[key] returns the value of the 'key' attribute for the tag, and throws an exception if it's not there.""" return self._getAttrMap()[key] def __iter__(self): "Iterating over a tag iterates over its contents." return iter(self.contents) def __len__(self): "The length of a tag is the length of its list of contents." return len(self.contents) def __contains__(self, x): return x in self.contents def __nonzero__(self): "A tag is non-None even if it has no contents." return True def __setitem__(self, key, value): """Setting tag[key] sets the value of the 'key' attribute for the tag.""" self._getAttrMap() self.attrMap[key] = value found = False for i in range(0, len(self.attrs)): if self.attrs[i][0] == key: self.attrs[i] = (key, value) found = True if not found: self.attrs.append((key, value)) self._getAttrMap()[key] = value def __delitem__(self, key): "Deleting tag[key] deletes all 'key' attributes for the tag." for item in self.attrs: if item[0] == key: self.attrs.remove(item) #We don't break because bad HTML can define the same #attribute multiple times. self._getAttrMap() if self.attrMap.has_key(key): del self.attrMap[key] def __call__(self, *args, **kwargs): """Calling a tag like a function is the same as calling its findAll() method. Eg. tag('a') returns a list of all the A tags found within this tag.""" return apply(self.findAll, args, kwargs) def __getattr__(self, tag): #print "Getattr %s.%s" % (self.__class__, tag) if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3: return self.find(tag[:-3]) elif tag.find('__') != 0: return self.find(tag) raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag) def __eq__(self, other): """Returns true iff this tag has the same name, the same attributes, and the same contents (recursively) as the given tag. NOTE: right now this will return false if two tags have the same attributes in a different order. Should this be fixed?""" if other is self: return True if not hasattr(other, 'name') or not hasattr(other, 'attrs') or not hasattr(other, 'contents') or self.name != other.name or self.attrs != other.attrs or len(self) != len(other): return False for i in range(0, len(self.contents)): if self.contents[i] != other.contents[i]: return False return True def __ne__(self, other): """Returns true iff this tag is not identical to the other tag, as defined in __eq__.""" return not self == other def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING): """Renders this tag as a string.""" return self.__str__(encoding) def __unicode__(self): return self.__str__(None) BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|" + "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)" + ")") def _sub_entity(self, x): """Used with a regular expression to substitute the appropriate XML entity for an XML special character.""" return "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";" def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING, prettyPrint=False, indentLevel=0): """Returns a string or Unicode representation of this tag and its contents. To get Unicode, pass None for encoding. NOTE: since Python's HTML parser consumes whitespace, this method is not certain to reproduce the whitespace present in the original string.""" encodedName = self.toEncoding(self.name, encoding) attrs = [] if self.attrs: for key, val in self.attrs: fmt = '%s="%s"' if isinstance(val, basestring): if self.containsSubstitutions and '%SOUP-ENCODING%' in val: val = self.substituteEncoding(val, encoding) # The attribute value either: # # * Contains no embedded double quotes or single quotes. # No problem: we enclose it in double quotes. # * Contains embedded single quotes. No problem: # double quotes work here too. # * Contains embedded double quotes. No problem: # we enclose it in single quotes. # * Embeds both single _and_ double quotes. This # can't happen naturally, but it can happen if # you modify an attribute value after parsing # the document. Now we have a bit of a # problem. We solve it by enclosing the # attribute in single quotes, and escaping any # embedded single quotes to XML entities. if '"' in val: fmt = "%s='%s'" if "'" in val: # TODO: replace with apos when # appropriate. val = val.replace("'", "&squot;") # Now we're okay w/r/t quotes. But the attribute # value might also contain angle brackets, or # ampersands that aren't part of entities. We need # to escape those to XML entities too. val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val) attrs.append(fmt % (self.toEncoding(key, encoding), self.toEncoding(val, encoding))) close = '' closeTag = '' if self.isSelfClosing: close = ' /' else: closeTag = '' % encodedName indentTag, indentContents = 0, 0 if prettyPrint: indentTag = indentLevel space = (' ' * (indentTag-1)) indentContents = indentTag + 1 contents = self.renderContents(encoding, prettyPrint, indentContents) if self.hidden: s = contents else: s = [] attributeString = '' if attrs: attributeString = ' ' + ' '.join(attrs) if prettyPrint: s.append(space) s.append('<%s%s%s>' % (encodedName, attributeString, close)) if prettyPrint: s.append("\n") s.append(contents) if prettyPrint and contents and contents[-1] != "\n": s.append("\n") if prettyPrint and closeTag: s.append(space) s.append(closeTag) if prettyPrint and closeTag and self.nextSibling: s.append("\n") s = ''.join(s) return s def decompose(self): """Recursively destroys the contents of this tree.""" self.extract() if len(self.contents) == 0: return current = self.contents[0] while current is not None: next = current.next if isinstance(current, Tag): del current.contents[:] current.parent = None current.previous = None current.previousSibling = None current.next = None current.nextSibling = None current = next def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING): return self.__str__(encoding, True) def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING, prettyPrint=False, indentLevel=0): """Renders the contents of this tag as a string in the given encoding. If encoding is None, returns a Unicode string..""" s=[] for c in self: text = None if isinstance(c, NavigableString): text = c.__str__(encoding) elif isinstance(c, Tag): s.append(c.__str__(encoding, prettyPrint, indentLevel)) if text and prettyPrint: text = text.strip() if text: if prettyPrint: s.append(" " * (indentLevel-1)) s.append(text) if prettyPrint: s.append("\n") return ''.join(s) #Soup methods def find(self, name=None, attrs={}, recursive=True, text=None, **kwargs): """Return only the first child of this Tag matching the given criteria.""" r = None l = self.findAll(name, attrs, recursive, text, 1, **kwargs) if l: r = l[0] return r findChild = find def findAll(self, name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs): """Extracts a list of Tag objects that match the given criteria. You can specify the name of the Tag and any attributes you want the Tag to have. The value of a key-value pair in the 'attrs' map can be a string, a list of strings, a regular expression object, or a callable that takes a string and returns whether or not the string matches for some custom definition of 'matches'. The same is true of the tag name.""" generator = self.recursiveChildGenerator if not recursive: generator = self.childGenerator return self._findAll(name, attrs, text, limit, generator, **kwargs) findChildren = findAll # Pre-3.x compatibility methods first = find fetch = findAll def fetchText(self, text=None, recursive=True, limit=None): return self.findAll(text=text, recursive=recursive, limit=limit) def firstText(self, text=None, recursive=True): return self.find(text=text, recursive=recursive) #Private methods def _getAttrMap(self): """Initializes a map representation of this tag's attributes, if not already initialized.""" if not getattr(self, 'attrMap'): self.attrMap = {} for (key, value) in self.attrs: self.attrMap[key] = value return self.attrMap #Generator methods def childGenerator(self): # Just use the iterator from the contents return iter(self.contents) def recursiveChildGenerator(self): if not len(self.contents): raise StopIteration stopNode = self._lastRecursiveChild().next current = self.contents[0] while current is not stopNode: yield current current = current.next # Next, a couple classes to represent queries and their results. class SoupStrainer: """Encapsulates a number of ways of matching a markup element (tag or text).""" def __init__(self, name=None, attrs={}, text=None, **kwargs): self.name = name if isinstance(attrs, basestring): kwargs['class'] = _match_css_class(attrs) attrs = None if kwargs: if attrs: attrs = attrs.copy() attrs.update(kwargs) else: attrs = kwargs self.attrs = attrs self.text = text def __str__(self): if self.text: return self.text else: return "%s|%s" % (self.name, self.attrs) def searchTag(self, markupName=None, markupAttrs={}): found = None markup = None if isinstance(markupName, Tag): markup = markupName markupAttrs = markup callFunctionWithTagData = callable(self.name) \ and not isinstance(markupName, Tag) if (not self.name) \ or callFunctionWithTagData \ or (markup and self._matches(markup, self.name)) \ or (not markup and self._matches(markupName, self.name)): if callFunctionWithTagData: match = self.name(markupName, markupAttrs) else: match = True markupAttrMap = None for attr, matchAgainst in self.attrs.items(): if not markupAttrMap: if hasattr(markupAttrs, 'get'): markupAttrMap = markupAttrs else: markupAttrMap = {} for k,v in markupAttrs: markupAttrMap[k] = v attrValue = markupAttrMap.get(attr) if not self._matches(attrValue, matchAgainst): match = False break if match: if markup: found = markup else: found = markupName return found def search(self, markup): #print 'looking for %s in %s' % (self, markup) found = None # If given a list of items, scan it for a text element that # matches. if hasattr(markup, "__iter__") \ and not isinstance(markup, Tag): for element in markup: if isinstance(element, NavigableString) \ and self.search(element): found = element break # If it's a Tag, make sure its name or attributes match. # Don't bother with Tags if we're searching for text. elif isinstance(markup, Tag): if not self.text: found = self.searchTag(markup) # If it's text, make sure the text matches. elif isinstance(markup, NavigableString) or \ isinstance(markup, basestring): if self._matches(markup, self.text): found = markup else: raise Exception, "I don't know how to match against a %s" \ % markup.__class__ return found def _matches(self, markup, matchAgainst): #print "Matching %s against %s" % (markup, matchAgainst) result = False if matchAgainst is True: result = markup is not None elif callable(matchAgainst): result = matchAgainst(markup) else: #Custom match methods take the tag as an argument, but all #other ways of matching match the tag name as a string. if isinstance(markup, Tag): markup = markup.name if markup and not isinstance(markup, basestring): markup = unicode(markup) #Now we know that chunk is either a string, or None. if hasattr(matchAgainst, 'match'): # It's a regexp object. result = markup and matchAgainst.search(markup) elif hasattr(matchAgainst, '__iter__'): # list-like result = markup in matchAgainst elif hasattr(matchAgainst, 'items'): result = markup.has_key(matchAgainst) elif matchAgainst and isinstance(markup, basestring): if isinstance(markup, unicode): matchAgainst = unicode(matchAgainst) else: matchAgainst = str(matchAgainst) if not result: result = matchAgainst == markup return result class ResultSet(list): """A ResultSet is just a list that keeps track of the SoupStrainer that created it.""" def __init__(self, source): list.__init__([]) self.source = source # Now, some helper functions. def buildTagMap(default, *args): """Turns a list of maps, lists, or scalars into a single map. Used to build the SELF_CLOSING_TAGS, NESTABLE_TAGS, and NESTING_RESET_TAGS maps out of lists and partial maps.""" built = {} for portion in args: if hasattr(portion, 'items'): #It's a map. Merge it. for k,v in portion.items(): built[k] = v elif hasattr(portion, '__iter__'): # is a list #It's a list. Map each item to the default. for k in portion: built[k] = default else: #It's a scalar. Map it to the default. built[portion] = default return built # Now, the parser classes. class BeautifulStoneSoup(Tag, SGMLParser): """This class contains the basic parser and search code. It defines a parser that knows nothing about tag behavior except for the following: You can't close a tag without closing all the tags it encloses. That is, "" actually means "". [Another possible explanation is "", but since this class defines no SELF_CLOSING_TAGS, it will never use that explanation.] This class is useful for parsing XML or made-up markup languages, or when BeautifulSoup makes an assumption counter to what you were expecting.""" SELF_CLOSING_TAGS = {} NESTABLE_TAGS = {} RESET_NESTING_TAGS = {} QUOTE_TAGS = {} PRESERVE_WHITESPACE_TAGS = [] MARKUP_MASSAGE = [(re.compile('(<[^<>]*)/>'), lambda x: x.group(1) + ' />'), (re.compile(']*)>'), lambda x: '') ] ROOT_TAG_NAME = u'[document]' HTML_ENTITIES = "html" XML_ENTITIES = "xml" XHTML_ENTITIES = "xhtml" # TODO: This only exists for backwards-compatibility ALL_ENTITIES = XHTML_ENTITIES # Used when determining whether a text node is all whitespace and # can be replaced with a single space. A text node that contains # fancy Unicode spaces (usually non-breaking) should be left # alone. STRIP_ASCII_SPACES = { 9: None, 10: None, 12: None, 13: None, 32: None, } def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None, markupMassage=True, smartQuotesTo=XML_ENTITIES, convertEntities=None, selfClosingTags=None, isHTML=False): """The Soup object is initialized as the 'root tag', and the provided markup (which can be a string or a file-like object) is fed into the underlying parser. sgmllib will process most bad HTML, and the BeautifulSoup class has some tricks for dealing with some HTML that kills sgmllib, but Beautiful Soup can nonetheless choke or lose data if your data uses self-closing tags or declarations incorrectly. By default, Beautiful Soup uses regexes to sanitize input, avoiding the vast majority of these problems. If the problems don't apply to you, pass in False for markupMassage, and you'll get better performance. The default parser massage techniques fix the two most common instances of invalid HTML that choke sgmllib:
(No space between name of closing tag and tag close) (Extraneous whitespace in declaration) You can pass in a custom list of (RE object, replace method) tuples to get Beautiful Soup to scrub your input the way you want.""" self.parseOnlyThese = parseOnlyThese self.fromEncoding = fromEncoding self.smartQuotesTo = smartQuotesTo self.convertEntities = convertEntities # Set the rules for how we'll deal with the entities we # encounter if self.convertEntities: # It doesn't make sense to convert encoded characters to # entities even while you're converting entities to Unicode. # Just convert it all to Unicode. self.smartQuotesTo = None if convertEntities == self.HTML_ENTITIES: self.convertXMLEntities = False self.convertHTMLEntities = True self.escapeUnrecognizedEntities = True elif convertEntities == self.XHTML_ENTITIES: self.convertXMLEntities = True self.convertHTMLEntities = True self.escapeUnrecognizedEntities = False elif convertEntities == self.XML_ENTITIES: self.convertXMLEntities = True self.convertHTMLEntities = False self.escapeUnrecognizedEntities = False else: self.convertXMLEntities = False self.convertHTMLEntities = False self.escapeUnrecognizedEntities = False self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags) SGMLParser.__init__(self) if hasattr(markup, 'read'): # It's a file-type object. markup = markup.read() self.markup = markup self.markupMassage = markupMassage try: self._feed(isHTML=isHTML) except StopParsing: pass self.markup = None # The markup can now be GCed def convert_charref(self, name): """This method fixes a bug in Python's SGMLParser.""" try: n = int(name) except ValueError: return if not 0 <= n <= 127 : # ASCII ends at 127, not 255 return return self.convert_codepoint(n) def _feed(self, inDocumentEncoding=None, isHTML=False): # Convert the document to Unicode. markup = self.markup if isinstance(markup, unicode): if not hasattr(self, 'originalEncoding'): self.originalEncoding = None else: dammit = UnicodeDammit\ (markup, [self.fromEncoding, inDocumentEncoding], smartQuotesTo=self.smartQuotesTo, isHTML=isHTML) markup = dammit.unicode self.originalEncoding = dammit.originalEncoding self.declaredHTMLEncoding = dammit.declaredHTMLEncoding if markup: if self.markupMassage: if not hasattr(self.markupMassage, "__iter__"): self.markupMassage = self.MARKUP_MASSAGE for fix, m in self.markupMassage: markup = fix.sub(m, markup) # TODO: We get rid of markupMassage so that the # soup object can be deepcopied later on. Some # Python installations can't copy regexes. If anyone # was relying on the existence of markupMassage, this # might cause problems. del(self.markupMassage) self.reset() SGMLParser.feed(self, markup) # Close out any unfinished strings and close all the open tags. self.endData() while self.currentTag.name != self.ROOT_TAG_NAME: self.popTag() def __getattr__(self, methodName): """This method routes method call requests to either the SGMLParser superclass or the Tag superclass, depending on the method name.""" #print "__getattr__ called on %s.%s" % (self.__class__, methodName) if methodName.startswith('start_') or methodName.startswith('end_') \ or methodName.startswith('do_'): return SGMLParser.__getattr__(self, methodName) elif not methodName.startswith('__'): return Tag.__getattr__(self, methodName) else: raise AttributeError def isSelfClosingTag(self, name): """Returns true iff the given string is the name of a self-closing tag according to this parser.""" return self.SELF_CLOSING_TAGS.has_key(name) \ or self.instanceSelfClosingTags.has_key(name) def reset(self): Tag.__init__(self, self, self.ROOT_TAG_NAME) self.hidden = 1 SGMLParser.reset(self) self.currentData = [] self.currentTag = None self.tagStack = [] self.quoteStack = [] self.pushTag(self) def popTag(self): tag = self.tagStack.pop() #print "Pop", tag.name if self.tagStack: self.currentTag = self.tagStack[-1] return self.currentTag def pushTag(self, tag): #print "Push", tag.name if self.currentTag: self.currentTag.contents.append(tag) self.tagStack.append(tag) self.currentTag = self.tagStack[-1] def endData(self, containerClass=NavigableString): if self.currentData: currentData = u''.join(self.currentData) if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and not set([tag.name for tag in self.tagStack]).intersection( self.PRESERVE_WHITESPACE_TAGS)): if '\n' in currentData: currentData = '\n' else: currentData = ' ' self.currentData = [] if self.parseOnlyThese and len(self.tagStack) <= 1 and \ (not self.parseOnlyThese.text or \ not self.parseOnlyThese.search(currentData)): return o = containerClass(currentData) o.setup(self.currentTag, self.previous) if self.previous: self.previous.next = o self.previous = o self.currentTag.contents.append(o) def _popToTag(self, name, inclusivePop=True): """Pops the tag stack up to and including the most recent instance of the given tag. If inclusivePop is false, pops the tag stack up to but *not* including the most recent instqance of the given tag.""" #print "Popping to %s" % name if name == self.ROOT_TAG_NAME: return numPops = 0 mostRecentTag = None for i in range(len(self.tagStack)-1, 0, -1): if name == self.tagStack[i].name: numPops = len(self.tagStack)-i break if not inclusivePop: numPops = numPops - 1 for i in range(0, numPops): mostRecentTag = self.popTag() return mostRecentTag def _smartPop(self, name): """We need to pop up to the previous tag of this type, unless one of this tag's nesting reset triggers comes between this tag and the previous tag of this type, OR unless this tag is a generic nesting trigger and another generic nesting trigger comes between this tag and the previous tag of this type. Examples:

FooBar *

* should pop to 'p', not 'b'.

FooBar *

* should pop to 'table', not 'p'.

Foo

Bar *

* should pop to 'tr', not 'p'.

    • *
    • * should pop to 'ul', not the first 'li'.
  • ** should pop to 'table', not the first 'tr' tag should implicitly close the previous tag within the same
    ** should pop to 'tr', not the first 'td' """ nestingResetTriggers = self.NESTABLE_TAGS.get(name) isNestable = nestingResetTriggers != None isResetNesting = self.RESET_NESTING_TAGS.has_key(name) popTo = None inclusive = True for i in range(len(self.tagStack)-1, 0, -1): p = self.tagStack[i] if (not p or p.name == name) and not isNestable: #Non-nestable tags get popped to the top or to their #last occurance. popTo = name break if (nestingResetTriggers is not None and p.name in nestingResetTriggers) \ or (nestingResetTriggers is None and isResetNesting and self.RESET_NESTING_TAGS.has_key(p.name)): #If we encounter one of the nesting reset triggers #peculiar to this tag, or we encounter another tag #that causes nesting to reset, pop up to but not #including that tag. popTo = p.name inclusive = False break p = p.parent if popTo: self._popToTag(popTo, inclusive) def unknown_starttag(self, name, attrs, selfClosing=0): #print "Start tag %s: %s" % (name, attrs) if self.quoteStack: #This is not a real tag. #print "<%s> is not real!" % name attrs = ''.join([' %s="%s"' % (x, y) for x, y in attrs]) self.handle_data('<%s%s>' % (name, attrs)) return self.endData() if not self.isSelfClosingTag(name) and not selfClosing: self._smartPop(name) if self.parseOnlyThese and len(self.tagStack) <= 1 \ and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)): return tag = Tag(self, name, attrs, self.currentTag, self.previous) if self.previous: self.previous.next = tag self.previous = tag self.pushTag(tag) if selfClosing or self.isSelfClosingTag(name): self.popTag() if name in self.QUOTE_TAGS: #print "Beginning quote (%s)" % name self.quoteStack.append(name) self.literal = 1 return tag def unknown_endtag(self, name): #print "End tag %s" % name if self.quoteStack and self.quoteStack[-1] != name: #This is not a real end tag. #print " is not real!" % name self.handle_data('' % name) return self.endData() self._popToTag(name) if self.quoteStack and self.quoteStack[-1] == name: self.quoteStack.pop() self.literal = (len(self.quoteStack) > 0) def handle_data(self, data): self.currentData.append(data) def _toStringSubclass(self, text, subclass): """Adds a certain piece of text to the tree as a NavigableString subclass.""" self.endData() self.handle_data(text) self.endData(subclass) def handle_pi(self, text): """Handle a processing instruction as a ProcessingInstruction object, possibly one with a %SOUP-ENCODING% slot into which an encoding will be plugged later.""" if text[:3] == "xml": text = u"xml version='1.0' encoding='%SOUP-ENCODING%'" self._toStringSubclass(text, ProcessingInstruction) def handle_comment(self, text): "Handle comments as Comment objects." self._toStringSubclass(text, Comment) def handle_charref(self, ref): "Handle character references as data." if self.convertEntities: data = unichr(int(ref)) else: data = '&#%s;' % ref self.handle_data(data) def handle_entityref(self, ref): """Handle entity references as data, possibly converting known HTML and/or XML entity references to the corresponding Unicode characters.""" data = None if self.convertHTMLEntities: try: data = unichr(name2codepoint[ref]) except KeyError: pass if not data and self.convertXMLEntities: data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref) if not data and self.convertHTMLEntities and \ not self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref): # TODO: We've got a problem here. We're told this is # an entity reference, but it's not an XML entity # reference or an HTML entity reference. Nonetheless, # the logical thing to do is to pass it through as an # unrecognized entity reference. # # Except: when the input is "&carol;" this function # will be called with input "carol". When the input is # "AT&T", this function will be called with input # "T". We have no way of knowing whether a semicolon # was present originally, so we don't know whether # this is an unknown entity or just a misplaced # ampersand. # # The more common case is a misplaced ampersand, so I # escape the ampersand and omit the trailing semicolon. data = "&%s" % ref if not data: # This case is different from the one above, because we # haven't already gone through a supposedly comprehensive # mapping of entities to Unicode characters. We might not # have gone through any mapping at all. So the chances are # very high that this is a real entity, and not a # misplaced ampersand. data = "&%s;" % ref self.handle_data(data) def handle_decl(self, data): "Handle DOCTYPEs and the like as Declaration objects." self._toStringSubclass(data, Declaration) def parse_declaration(self, i): """Treat a bogus SGML declaration as raw data. Treat a CDATA declaration as a CData object.""" j = None if self.rawdata[i:i+9] == '', i) if k == -1: k = len(self.rawdata) data = self.rawdata[i+9:k] j = k+3 self._toStringSubclass(data, CData) else: try: j = SGMLParser.parse_declaration(self, i) except SGMLParseError: toHandle = self.rawdata[i:] self.handle_data(toHandle) j = i + len(toHandle) return j class BeautifulSoup(BeautifulStoneSoup): """This parser knows the following facts about HTML: * Some tags have no closing tag and should be interpreted as being closed as soon as they are encountered. * The text inside some tags (ie. 'script') may contain tags which are not really part of the document and which should be parsed as text, not tags. If you want to parse the text as tags, you can always fetch it and parse it explicitly. * Tag nesting rules: Most tags can't be nested at all. For instance, the occurance of a

    tag should implicitly close the previous

    tag.

    Para1

    Para2 should be transformed into:

    Para1

    Para2 Some tags can be nested arbitrarily. For instance, the occurance of a

    tag should _not_ implicitly close the previous
    tag. Alice said:
    Bob said:
    Blah should NOT be transformed into: Alice said:
    Bob said:
    Blah Some tags can be nested, but the nesting is reset by the interposition of other tags. For instance, a
    , but not close a tag in another table.
    BlahBlah should be transformed into:
    BlahBlah but, Blah
    Blah should NOT be transformed into Blah
    Blah Differing assumptions about tag nesting rules are a major source of problems with the BeautifulSoup class. If BeautifulSoup is not treating as nestable a tag your page author treats as nestable, try ICantBelieveItsBeautifulSoup, MinimalSoup, or BeautifulStoneSoup before writing your own subclass.""" def __init__(self, *args, **kwargs): if not kwargs.has_key('smartQuotesTo'): kwargs['smartQuotesTo'] = self.HTML_ENTITIES kwargs['isHTML'] = True BeautifulStoneSoup.__init__(self, *args, **kwargs) SELF_CLOSING_TAGS = buildTagMap(None, ('br' , 'hr', 'input', 'img', 'meta', 'spacer', 'link', 'frame', 'base', 'col')) PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea']) QUOTE_TAGS = {'script' : None, 'textarea' : None} #According to the HTML standard, each of these inline tags can #contain another tag of the same type. Furthermore, it's common #to actually use these tags this way. NESTABLE_INLINE_TAGS = ('span', 'font', 'q', 'object', 'bdo', 'sub', 'sup', 'center') #According to the HTML standard, these block tags can contain #another tag of the same type. Furthermore, it's common #to actually use these tags this way. NESTABLE_BLOCK_TAGS = ('blockquote', 'div', 'fieldset', 'ins', 'del') #Lists can contain other lists, but there are restrictions. NESTABLE_LIST_TAGS = { 'ol' : [], 'ul' : [], 'li' : ['ul', 'ol'], 'dl' : [], 'dd' : ['dl'], 'dt' : ['dl'] } #Tables can contain other tables, but there are restrictions. NESTABLE_TABLE_TAGS = {'table' : [], 'tr' : ['table', 'tbody', 'tfoot', 'thead'], 'td' : ['tr'], 'th' : ['tr'], 'thead' : ['table'], 'tbody' : ['table'], 'tfoot' : ['table'], } NON_NESTABLE_BLOCK_TAGS = ('address', 'form', 'p', 'pre') #If one of these tags is encountered, all tags up to the next tag of #this type are popped. RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript', NON_NESTABLE_BLOCK_TAGS, NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS) NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS, NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS) # Used to detect the charset in a META tag; see start_meta CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M) def start_meta(self, attrs): """Beautiful Soup can detect a charset included in a META tag, try to convert the document to that charset, and re-parse the document from the beginning.""" httpEquiv = None contentType = None contentTypeIndex = None tagNeedsEncodingSubstitution = False for i in range(0, len(attrs)): key, value = attrs[i] key = key.lower() if key == 'http-equiv': httpEquiv = value elif key == 'content': contentType = value contentTypeIndex = i if httpEquiv and contentType: # It's an interesting meta tag. match = self.CHARSET_RE.search(contentType) if match: if (self.declaredHTMLEncoding is not None or self.originalEncoding == self.fromEncoding): # An HTML encoding was sniffed while converting # the document to Unicode, or an HTML encoding was # sniffed during a previous pass through the # document, or an encoding was specified # explicitly and it worked. Rewrite the meta tag. def rewrite(match): return match.group(1) + "%SOUP-ENCODING%" newAttr = self.CHARSET_RE.sub(rewrite, contentType) attrs[contentTypeIndex] = (attrs[contentTypeIndex][0], newAttr) tagNeedsEncodingSubstitution = True else: # This is our first pass through the document. # Go through it again with the encoding information. newCharset = match.group(3) if newCharset and newCharset != self.originalEncoding: self.declaredHTMLEncoding = newCharset self._feed(self.declaredHTMLEncoding) raise StopParsing pass tag = self.unknown_starttag("meta", attrs) if tag and tagNeedsEncodingSubstitution: tag.containsSubstitutions = True class StopParsing(Exception): pass class ICantBelieveItsBeautifulSoup(BeautifulSoup): """The BeautifulSoup class is oriented towards skipping over common HTML errors like unclosed tags. However, sometimes it makes errors of its own. For instance, consider this fragment: FooBar This is perfectly valid (if bizarre) HTML. However, the BeautifulSoup class will implicitly close the first b tag when it encounters the second 'b'. It will think the author wrote "FooBar", and didn't close the first 'b' tag, because there's no real-world reason to bold something that's already bold. When it encounters '' it will close two more 'b' tags, for a grand total of three tags closed instead of two. This can throw off the rest of your document structure. The same is true of a number of other tags, listed below. It's much more common for someone to forget to close a 'b' tag than to actually use nested 'b' tags, and the BeautifulSoup class handles the common case. This class handles the not-co-common case: where you can't believe someone wrote what they did, but it's valid HTML and BeautifulSoup screwed up by assuming it wouldn't be.""" I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \ ('em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong', 'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b', 'big') I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ('noscript',) NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS, I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS, I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS) class MinimalSoup(BeautifulSoup): """The MinimalSoup class is for parsing HTML that contains pathologically bad markup. It makes no assumptions about tag nesting, but it does know which tags are self-closing, that