diff options
author | Midas <vdrportal_midas@gmx.de> | 2010-11-05 01:09:35 +0100 |
---|---|---|
committer | Midas <vdrportal_midas@gmx.de> | 2010-11-05 01:09:35 +0100 |
commit | ff03def766c15182ffcada0d2e6b57d154bcd0c2 (patch) | |
tree | 8b79bc3bfff07d946aa9febc4fac47ea4b07cbd5 | |
parent | f55dac3011baefcb9a92d9fc046a72afe08bf9ec (diff) | |
download | vdr-plugin-block-ff03def766c15182ffcada0d2e6b57d154bcd0c2.tar.gz vdr-plugin-block-ff03def766c15182ffcada0d2e6b57d154bcd0c2.tar.bz2 |
Release of Version 0.1.0
New features / Bugfixes:
-Feature: block.conf format and path changed
-Feature: Whitelist function
-Feature: New Setup Option 'Fuzzy Fallback' (see whitelist section above)
-Feature: Duplicate entries are not allowed anymore!
-Feature: New key handling in the plugins setup
-Feature: 'New' jumps to an existing 'New entry'
-Feature: Parental Guidance and main menu entry
-Feature: In Parental Guidance mode replay may be blocked
-Feature: Consideration of empty or no EPG data
-Feature: Italian translation added (thanks to Diego Pierotto)
-Feature: Added list sorting.
-Feature: Changes are applied immediately.
-Bugfix: In rare cases shows were not blocked. Fixed.
-Bugfix: Zap direction
-Bugfix: Changing the zap direction on block events to 'down' should now work (again).
-Bugfix: Unwanted behaviour if OSD is open
-Bugfix: Syslog spams on channels with no or empty EPG
please see HISTORY and README for more details
-rw-r--r-- | HISTORY | 105 | ||||
-rw-r--r-- | README | 80 | ||||
-rw-r--r-- | block.c | 384 | ||||
-rw-r--r-- | common.h | 3 | ||||
-rw-r--r-- | config.c | 16 | ||||
-rw-r--r-- | config.h | 10 | ||||
-rw-r--r-- | control.c | 54 | ||||
-rw-r--r-- | control.h | 1 | ||||
-rw-r--r-- | event.c | 303 | ||||
-rw-r--r-- | event.h | 29 | ||||
-rw-r--r-- | i18n.c | 144 | ||||
-rw-r--r-- | po/de_DE.po | 29 | ||||
-rw-r--r-- | po/it_IT.po | 84 | ||||
-rw-r--r-- | setup.c | 193 | ||||
-rw-r--r-- | setup.h | 2 | ||||
-rw-r--r-- | status.c | 46 | ||||
-rw-r--r-- | status.h | 2 |
17 files changed, 1163 insertions, 322 deletions
@@ -1,6 +1,111 @@ VDR Plugin 'block' Revision History ----------------------------------- +2010/11/04: Version 0.1.0 + +New features / Bugfixes: +-Feature: block.conf format and path changed + The blacklist was formerly stored in $VDRCONFIG\plugins. As this is also used by several other plugins + the directory might rapidly become overpopulated. I decided to move the location of block.conf to + $VDRCONFIG/plugins/block. To your convenienve you won't have to move the file manually. It is moved the first + time you start vdr after installing at least version 0.1.0 of the block-plugin. + Please note that during this process the file is also scanned for (case-insensitive) duplicates which will + be sorted out (syslogged as 'WARNINGS') as well as all entries will be marked blacklisted due to the new + blacklist/whitelist feature since version 0.1.0. It doesn't matter if you are upgrading from the taste-plugin + or a former version of the block-plugin, the plugin should choose the right file (if there is one) + automatically. Though the plugin was tested quite a lot, it might be very good idea to create a BACKUP before + you upgrade the block plugin. Nevertheless the plugin itself should create a backup of the old file in + $VDRCONFIG/plugins/block/block.conf.safe-pre0.1.0 automatically. + +-Feature: Whitelist function + The most relevant new feature in this version is probably the possibility not only to blacklist entries in + the plugins list but also to whitelist them! This should make the use of the parental guidance feature much + easier for example. In this context the use of regular expressions, partial patterns, blacklist and whitelist + entries easily results in contradictory rules for a particular entry and made it necessary to implement a new + evaluation pathway. The best thing about this is that you still just have to press De-/Block in the vdr main + menu to make use of the plugin. The changes in the evaluation pathway will be applied automatically in the + background. As i think the usage of the plugin is kept as easy as possible, you could skip the description of + the decision pathway. Nevertheless the following describes happens behind the curtains, if a string is checked + for being acceptable or not: + 1. First all matching entries are collected. + 2. If all rules point to the same condition (blacklisted or whitelisted) this results in returning this particular + condition. + 3. If contradictory rules are detected, the plugin falls back to the value of a new option in the plugins setup + which was implemented exactly for these cases: Fuzzy fallback {black|white}. + 4. The above rules are overridden if there is a case-insensitive exact string match found in the plugins list. + In this case the plugin will just switch the list property of this match from black to white or vice versa + instead of creating a duplicate. In case the string match is only case insensitive the plugin furthermore + switches the ignore case property of the entry. + + To make ultimate use of the plugin (probably makes sense in turn with parental guidance mode and whitelist entries) + you could add a new entry in the plugins list: + [.]* + and set the property Regular Expression to true. This should block every, read carefully, EVERY show on any + channel, except for those being whitelisted. Remember, once Parental Guidance is turned on you are not allowed + to whitelist anything anymore...until you switch it off in vdr's setup file again. Handle with care! + +-Feature: New Setup Option 'Fuzzy Fallback' (see whitelist section above) + +-Feature: Duplicate entries are not allowed anymore! + At the first import of block.conf the plugin will eliminate all duplicates from your old blacklist. However you do + not have to care about duplicates yourself. The plugin should configure everythin automatically. (please also refer + to the block.conf section above) + +-Feature: New key handling in the plugins setup + F4/Blue now changes the black/white attribute of the current entry (see whitelist section above). Please note + that it could take a short time to let the plugin find the right entry internally. This is due to the implementation + of cList in vdr itself. + +-Feature: 'New' jumps to an existing 'New entry' + This comes along with the new prohibition of duplicate entries and should increase convenience. As stated in the + last section, it could take some time to let the plugin find the right place. Again this is due to the implementation + of cList in vdr itself. + +-Feature: Parental Guidance and main menu entry + If Parental Guidance is active it shouldn't be possible to deblock the current show with the main menu entry. + Any attempt to do this is logged in the syslog. + +-Feature: In Parental Guidance mode replay may be blocked + In Parental Guidance mode now also the replay of recorded shows is blocked, if a blacklisted title is + detected. Any attempt to play such a blocked recording also is logged in the syslog. However it is not possible + to block recorded shows directly. You'll have to have a matching list entry by blocking the corresponding show + on Live TV, by manually adding it in the plugins setup or by editing block.conf (vdr restart required). + +-Feature: Consideration of empty or no EPG data + Channels with empty EPG or no EPG at all may also be handled by the plugin now. Use regular expressions + or a blank list entry to deal with such stations. (see regular expression in the whitelist section above for an + example). However if your EPG turns out to be buggy or vdr does not update EPG fast enough, such an entry may cause + unwanted behaviour of the block mechanism in rare cases. + +-Feature: Italian translation added (thanks to Diego Pierotto) + Due to the new features few strings remain untranslated (though i added some...). + If anyone could help out with this or other translations feel free drop me a line. + +-Feature: Added list sorting. + +-Feature: Changes are applied immediately. + The plugin now immediately applies any changes to the block rules, eg in case anything in the list is altered + (and saved) in the plugins setup. + +-Bugfix: In rare cases shows were not blocked. Fixed. + If the current channel had the same blacklisted EPG title as the last channel the current channel was not blocked. + Fixed. Thanks to igel, who again was the only one reporting this bug. + +-Bugfix: Zap direction + The automatical zap direction should now be detected correctly (except it is not possible to determine + which results in direction 'up') + +-Bugfix: Changing the zap direction on block events to 'down' should now work (again). + +-Bugfix: Unwanted behaviour if OSD is open + A very nasty bug emerged if a block event happened on the underlying channel while the user was doing something + in the vdr OSD menus. In fact the plugin triggered a virtual keypress of the Back which in the worst case could + result in an irresponsive main menu. This bug which was caused by the plugins user interface during the display of + the block message is now fixed. The plugin simply switches channels and does not provide a user interface if + the vdr OSD is open. + +-Bugfix: Log message was not ifdef'ed and spammed the syslog on channels with no or empty EPG though LOGGING was off. +************************************************************************** 2010/08/06: Version 0.0.4 New Features: -The main menu entry now not only adds the title of the current @@ -29,21 +29,34 @@ another channel. Unwanted shows are identified by their EPG title in a predefined blacklist. You can add the current title to the block plugin blacklist by choosing -'Block Broadcast' from the main VDR menu or by editing the blacklist in the -setup of the plugin. In the latter case make sure you close the submenus as -well as the setup menu by 'ok' to properly save your changes. This would -also be the right place to remove entries from the blacklist. - +'De-/Block Broadcast' from the main VDR menu or by editing the blacklist in +the setup of the plugin. In the latter case make sure you close the submenus +as well as the setup menu by 'ok' to properly save your changes. This would +also be the right place to remove entries from the blacklist. Once a show is +blocked you could also deblock the current show by again choosing +'De-/Block Broadcast' from the main menu, while the show is running on the +current channel. + +There are two detection methods which can be chosen in the plugins setup +under 'Detection Method' - On Switch or Channel EPG. +On Switch: Every time the VDR switches to another channel the block plugin checks if the EPG title of the current show matches with a blacklist entry and if so the show won't be displayed and after a configurable pause (default 2s) the VDR switches to another channel automatically. Usually this will be the next possible lower channel number if you were coming from a higher one or vice-versa. If this is not possible, the vdr switches to the last channel -displayed. Of course you can zap to another channel yourself as well. +displayed. +Channel EPG: +If set to this option the plugin scans the epg title not only on channel +switches but it will scan permanently. This way also block events in the +current channel are detected. This is mandatory for parental guidance mode +and automatically set in this mode. In case you unexpectedly want to watch a blacklisted show you can override -the block rule by pressing 'Ok' while the message is displayed. +the block rule by pressing 'Ok' while the message is displayed. This +behaviour can be deactivated in the plugins setup (automatically in parental +guidance mode). For VDR versions <= 1.3.16 you will have to apply the included patch to the VDR source in order to have multiple channels being blocked in a row. @@ -62,13 +75,19 @@ Block current show: Choose 'Block Broadcast' from the main vdr menu. -Edit, delete or manually add new entries: ------------------------------------------ +Edit, white/blacklist, delete or manually add new entries: +---------------------------------------------------------- Go to the plugins setup in the vdr menu, where you will find the blacklist. Use the color keys as shown in the osd. Editing additionally allows you to ignore case, or to use regular -expressions. +expressions and to white/blacklist the entry. +In Parental Guidance mode it is only possible to add entries and editing +is restricted to new entries and to changes to the pattern and regular +expression mode. +Black/whitelisting is switched by choosing the main menu entry of the +plugin and can also be changed in the plugins pattern list (by blue/F4) +or in the editing view of an entry. Setup Options: @@ -79,7 +98,7 @@ Hide main menu entry: Shows/doesn't show the block plugin main menu entry. Timeout: Defines how long the block osd message is displayed, before the plugin switches to another channel. -Method: In version 0.0.2 there was a new detection method added. You can +Method: In version 0.0.2 there a new detection method was added. You can choose between 'On Switch' which is the old method that only scans at zap events. The other method is 'Channel EPG' which scans the current epg title permanentely. If you are setting up a parental @@ -92,13 +111,18 @@ Ok deblocks temporarily: If set to yes this allows a blocked show to be guidance config you want to set this to 'no' (see below). +Fuzzy Fallback: As of version 0.1.0 whitelisting function was added which + could lead to contradictory rules for a list entry. If so + the plugin falls back to the value fo Fuzzy Fallback which + could be set to black or white. + Parental Guidance Setup (Experimental as of version 0.0.2+dev): --------------------------------------- First of all: I can't guarantee a perfectly failsafe childprotection. - Feel free to test the Parental Guidance Config at your + Feel free to test the Parental Guidance config at your own risk but don't forget, that it is you not me who takes care of your children. Nevertheless the method used by the plugin should work quite good, as long as @@ -106,23 +130,35 @@ First of all: I can't guarantee a perfectly failsafe childprotection. with the current show. How to: Several prerequisites have to be configured in the plugins - setup. For your convenience these are set by manually adding + setup. For your convenience these are set by manually adding + or setting block.ParentalGuidance=1 to vdrs setup.conf. vdr has to be stopped before you edit the file, otherwise it will be overwritten the - next time vdr stops and your changes will be lost. + next time vdr stops and your changes will be lost. Note that + once the setting has been added to setup.conf the only way + to deactivate parental guidance mode is to set + + block.ParentalGuidance=0 + + (again with vdr being stopped) or by removing the row from + setup.conf. + + Setting ParentalGuidance to 1 overrides three other setup + options: 'Detection Method' is set to 'Channel EPG', + 'Ok deblocks temporarily' is set to 'No' and 'Fuzzy fallback' + is set to 'black', as obviously other settings would undermine + Parental Guidance mode. Furthermore the color keys yellow + (Delete) and blue (switch black/white) are deactivated in the + plugins setup. Editing is only allowed for new entries, for + which you are only allowed to change the pattern and to set + regular expression mode. - Setting ParentalGuidance to 1 overrides two other setup - options: Detection Method is set to 'Channel EPG' and - Ok deblocks temporarily is set to 'No', as obviously - other settings would undermine Parental Guidance mode. - Furthermore the color keys (Edit, New, Delete) are - deactivated in the plugins setup. -Finally improvements may depend on your feeback, so please drop me a line +Finally improvements may depend on your feedback, so please drop me a line if you experience any kind of potential misbehaviour of the plugin, if you have suggestions how to make the block plugin better etc. or if you just -want to say thank you ;) !
\ No newline at end of file +want to say thank you ;) ! @@ -9,19 +9,18 @@ * */ -#include <getopt.h> #include <vdr/plugin.h> +#include <vdr/menu.h> #include "status.h" -#include "event.h" #include "setup.h" -#include "config.h" -#include "i18n.h" #include "control.h" -#include "common.h" -#include <vdr/interface.h> -static const char *VERSION = "0.0.4+201008090412"; +#include <fstream> +using namespace std; + + +static const char *VERSION = "0.1.0"; static const char *DESCRIPTION = trNOOP("Block unwanted shows by EPG title"); static const char *MAINMENUENTRY = trNOOP("(De)Block broadcast"); @@ -56,7 +55,7 @@ cPluginBlock::cPluginBlock(void): cPlugin(), mStatus(NULL) { - cEventBlock::LastTitle=(char*)"block_dummy_title1"; + cEventBlock::LastTitle=(char*)"vdr plugin block started"; } cPluginBlock::~cPluginBlock() @@ -66,7 +65,88 @@ cPluginBlock::~cPluginBlock() bool cPluginBlock::Initialize(void) { - return EventsBlock.Load(AddDirectory(cPlugin::ConfigDirectory(), "block.conf"), true, false); + char* blacklist_path=NULL; + int io_result=-1; + asprintf(&blacklist_path,"%s/%s",cPlugin::ConfigDirectory(),"block"); + io_result=mkdir (blacklist_path, S_IRWXU); + + if (errno==EEXIST) dsyslog("plugin-block: path '%s' seems to exist...ok.",blacklist_path); + else if (errno==EPERM) dsyslog("plugin-block: ERROR: Permission denied accessing '%s'",blacklist_path); + else if (io_result==0) dsyslog("plugin-block: path '%s' was created...ok.",blacklist_path); + else dsyslog("plugin-block: ERROR: Accessing '%s'! Doesn't seem to exist though permissions seem to be ok.",blacklist_path); + + char* blacklist_file=NULL; + + asprintf(&blacklist_file,"%s/block.conf",blacklist_path); //block.conf in new place (config/block/block.conf) ? + io_result=access(blacklist_file,F_OK); + + if (io_result==-1) //not there lets check the old places + { + dsyslog("plugin-block: '%s' doesn't exist. Checking old paths.",blacklist_file); + char* source_file=NULL; + asprintf(&source_file,"%s/block.conf",cPlugin::ConfigDirectory()); + io_result=access(source_file,F_OK); + if (io_result==-1) //also no file config/block.conf (old path) + { + dsyslog("plugin-block: '%s' doesn't exist. Looking for taste.conf.",source_file); + source_file=NULL; + asprintf(&source_file,"%s/taste.conf",cPlugin::ConfigDirectory()); + io_result=access(source_file,F_OK); + if (io_result==-1) // config/taste.conf also does not exist (very old path) + { + dsyslog("plugin-block: '%s' doesn't exist. Giving up.",source_file); + dsyslog("plugin-block: WARNING: No block.conf or taste.conf found!"); + source_file=NULL; + } + } + if (source_file!=NULL) + { + dsyslog("plugin-block: source %s, dest %s",source_file,blacklist_file); + ifstream infile(source_file); + ofstream outfile(blacklist_file); + outfile<<infile.rdbuf(); + infile.close(); + outfile.close(); + } + } + + char* backup_file=NULL; + asprintf(&backup_file,"%s.safe-pre0.1.0",blacklist_file); + + if (access(backup_file,F_OK)==-1) //backup not found + { + if (access(blacklist_file,F_OK)==0) //ok, now that we have a block.conf file in the right path do the backup + { + ifstream infile(blacklist_file); + ofstream outfile(backup_file); + outfile<<infile.rdbuf(); + infile.close(); + outfile.close(); + } + } + + bool b = EventsBlock.Load(AddDirectory(cPlugin::ConfigDirectory(), "block/block.conf"), true, false); + EventsBlock.Sort(); + cEventBlock* listptr=EventsBlock.First(); + while (listptr!=NULL) + { + if (listptr->Next()==NULL) break; + const char* src=cEventBlock::duptolower(listptr->Pattern()); + const char* cmp=cEventBlock::duptolower(((cEventBlock*)listptr->Next())->Pattern()); +#ifdef LOGGING + dsyslog("plugin-block: Checking for duplicates (case insensitive): '%s' and '%s'",src,cmp); +#endif + if (strcmp(src,cmp)==0) + { + dsyslog("plugin-block: WARNING - import taste|block.conf: deleting duplicate entry %s",cmp); + EventsBlock.Del(listptr->Next(),true); + continue; + } + listptr=EventsBlock.Next(listptr); + } + + cSetupBlock::LastcChannel=Channels.GetByNumber(cDevice::CurrentChannel()); + return b; } bool cPluginBlock::Start(void) @@ -78,85 +158,121 @@ bool cPluginBlock::Start(void) return true; } + cOsdObject *cPluginBlock::MainMenuAction(void) { const cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel()); - if (channel != NULL && !channel->GroupSep()) { + const char* current_title=NULL; + if (channel != NULL && !channel->GroupSep()) + { cSchedulesLock schedLock; const cSchedules *scheds = cSchedules::Schedules(schedLock); - if (scheds == NULL) - return NULL; + if (scheds != NULL) + { + const cSchedule *sched = scheds->GetSchedule(channel->GetChannelID()); + if (sched != NULL) + { + const cEvent *present = sched->GetPresentEvent(); + if (present != NULL) + current_title=present->Title(); + } + } + } + if (current_title==NULL) current_title=""; + + bool acceptable=EventsBlock.Acceptable(current_title); - const cSchedule *sched = scheds->GetSchedule(channel->GetChannelID()); - if (sched == NULL) - return NULL; - const cEvent *present = sched->GetPresentEvent(); - - if (EventsBlock.Acceptable(present->Title())) + + if (!acceptable && cSetupBlock::ParentalGuidance)//TODO check if works { - EventsBlock.Add(new cEventBlock(present->Title())); - EventsBlock.Sort(); - EventsBlock.Save(); + dsyslog("plugin-block: Parental Guidance: Attempt to deblock '%s' from main menu! Permission denied!",current_title); + cSkinDisplayChannel* mOsd = Skins.Current()->DisplayChannel(true); + mOsd->SetMessage(mtError, tr("Permission denied!")); + mOsd->Flush(); + return NULL; } - else + cEventBlock* stringmatch=NULL; + stringmatch=EventsBlock.hasStringMatch(current_title,true); + if (stringmatch!=NULL) { - int index=0; - const cEventBlock* blockeventpointer = EventsBlock.First(); - while (blockeventpointer != NULL) - { - if (strcmp(blockeventpointer->Pattern(),present->Title())==0) - break; - index+=1; - blockeventpointer=EventsBlock.Next(blockeventpointer); - } - cEventBlock *event=EventsBlock.Get(index); - if (event!=NULL) + bool case_insensitive_match=strcmp(stringmatch->Pattern(),current_title); + if (case_insensitive_match) { - if (Interface->Confirm(tr("Delete keyword?"))) - EventsBlock.Del(event); - EventsBlock.Save(); + stringmatch->setIgnoreCase(true); } + stringmatch->setWhitelisted(!acceptable); + EventsBlock.Save(); + cEventBlock::LastTitle="force recheck from main menu"; } - - cEventBlock::LastTitle="block_dummy_title2"; - } + else //create a new enrty + { + cEventBlock *new_entry=new cEventBlock(current_title); + new_entry->setWhitelisted(!acceptable); + EventsBlock.Add(new_entry); + EventsBlock.Sort(); + EventsBlock.Save(); + cEventBlock::LastTitle="force recheck from main menu"; + + } + return NULL; -} +} + cMenuSetupPage *cPluginBlock::SetupMenu(void) { return new cMenuSetupBlock(); } + bool cPluginBlock::SetupParse(const char *Name, const char *Value) { return SetupBlock.Parse(Name, Value); } + void cPluginBlock::MainThreadHook() { - if (cSetupBlock::DetectionMethod!=1) { -#ifdef LOGGING - dsyslog("plugin-block: MainThreadHook returned because other detection method active in setup"); -#endif - return;//other detection method active in setup +// +// commented out cause spams the syslog: +// +// #ifdef LOGGING +// dsyslog("plugin-block: MainThreadHook returned because other detection method active in setup"); +// #endif + return;//other detection method active in setup } if (cEventBlock::ReplayingRecording) //no block events on the underlying channel processed - user watches recording { -#ifdef LOGGING + #ifdef LOGGING if (!temp_replaying_recording) { temp_replaying_recording=true; + #endif + if (cSetupBlock::ParentalGuidance==1) + { + while (cSetupBlock::ReplayingName==NULL); + if (!EventsBlock.Acceptable(cSetupBlock::ReplayingName)) + { + dsyslog("plugin-block: Parental Guidance detected attempt to replay recording with blocked title '%s'! Permission denied!",cSetupBlock::ReplayingName); + int destination=cSetupBlock::LastAcceptableChannel; + if (destination==0) destination=cDevice::CurrentChannel(); + cDevice::PrimaryDevice()->SwitchChannel(Channels.GetByNumber(destination),true); + Skins.Message(mtError, tr("Permission denied!")); + cEventBlock::LastTitle=(char*)"parental guidance event"; + return; + } + } + #ifdef LOGGING dsyslog("plugin-block: doing nothing because user watches recording"); } -#endif + #endif return; } -#ifdef LOGGING + #ifdef LOGGING else { if (temp_replaying_recording) @@ -165,99 +281,141 @@ void cPluginBlock::MainThreadHook() dsyslog("plugin-block: replay of recording ended. Resuming detection mode."); } } -#endif - - channelnumber=cDevice::PrimaryDevice()->CurrentChannel(); - if (channelnumber==0) + #endif + channelnumber=cDevice::CurrentChannel(); + if (channelnumber==0) //TODO last check revealed this possibly would never be true because ChannelSwitch handles it? { -#ifdef LOGGING + #ifdef LOGGING dsyslog("plugin-block: Channel number is 0 => Channel switch on primary device"); -#endif + #endif return; //switch in progress } - const cChannel *channel=Channels.GetByNumber(channelnumber); - + + if (cSetupBlock::LastcChannel!=channel)//necessary cause otherwise switching from one channel to another with both having + //the same blocked EPG title would result in the second channel not being + //blocked (more precise: until a different EPG title is analysed) + { + cEventBlock::LastTitle=(char*)"assuming Channelswitch"; + #ifdef LOGGING + if (cSetupBlock::LastcChannel!=NULL && channel!=NULL) dsyslog("plugin-block: current channel changed (%i->%i)- switching? using dummy for LastTitle: %s",cSetupBlock::LastcChannel->Number(), channel->Number(),cEventBlock::LastTitle); + #endif + } + const char* title=NULL; + const cEvent *present=NULL; + const cEvent *follow=NULL; if (channel != NULL && !channel->GroupSep()) { -#ifdef LOGGING - char *temp_string; - asprintf(&temp_string,"channel: %d channel->GroupSep(): %d", channel->Number(), channel->GroupSep()); - if (strcmp(temp_string,channel_groupsep_string)!=0) - { - dsyslog("plugin-block: %s",temp_string); - channel_groupsep_string=temp_string; - } -#endif - cSchedulesLock schedLock; - const cSchedules *scheds = cSchedules::Schedules(schedLock); - - if (scheds == NULL) - { - char *dummy=cEventBlock::getTimeStamp(); - dsyslog("plugin-block: no EPG data (scheds==NULL) - using dummy for LastTitle: %s",dummy); - cEventBlock::LastTitle=(char*)dummy; - return; - } - + /*//only for debugging purposes: + #ifdef LOGGING + char *temp_string; + asprintf(&temp_string,"channel: %d channel->GroupSep(): %d", channel->Number(), channel->GroupSep()); + if (strcmp(temp_string,channel_groupsep_string)!=0) + { + dsyslog("plugin-block: %s",temp_string); + channel_groupsep_string=temp_string; + } + #endif + */ + + + + + cSchedulesLock schedLock; + const cSchedules *scheds = cSchedules::Schedules(schedLock); + + if (scheds != NULL) + { const cSchedule *sched = scheds->GetSchedule(channel->GetChannelID()); - if (sched == NULL) + if (sched != NULL) { - char *dummy=cEventBlock::getTimeStamp(); - dsyslog("plugin-block: no EPG data (sched==NULL) - using dummy for LastTitle: %s",dummy); - cEventBlock::LastTitle=(char*)dummy; - return; + present = sched->GetPresentEvent(); + follow = sched->GetFollowingEvent(); + if (present!=NULL) + title=present->Title(); } - - const cEvent *present = sched->GetPresentEvent(); - const cEvent *follow = sched->GetFollowingEvent(); - - if (present == NULL) - { - char *dummy=cEventBlock::getTimeStamp(); - dsyslog("plugin-block: no EPG title (present==NULL) - using dummy for LastTitle: %s",dummy); - cEventBlock::LastTitle=(char*)dummy; - return; - } - - //TODO: check if isrequested is still necessary -// if (!cControlBlock::IsRequested() && !EventsBlock.Acceptable(present->Title())) - const char* title=present->Title(); - if (strcmp(title,"")==0) //dunno if this could ever be reached (most likely any of the above would be NULL before) - { - char *dummy=cEventBlock::getTimeStamp(); - dsyslog("plugin-block: no EPG title ("") - using dummy for LastTitle: %s",dummy); - cEventBlock::LastTitle=(char*)dummy; - return; - } - + } + } + if (title==NULL) title=""; + if (strcmp(title,cEventBlock::LastTitle)==0) { -#ifdef LOGGING + #ifdef LOGGING char *temp_string; asprintf(&temp_string, "'%s' has already been checked",title); if (strcmp(temp_string,has_been_checked_string)!=0) { - dsyslog("plugin-block: %s",temp_string); - has_been_checked_string=temp_string; + dsyslog("plugin-block: %s",temp_string); //outputs: 'bla' has already been checked + has_been_checked_string=temp_string; //TODO a bool may increase performance } -#endif + #endif return; //current show has already been checked } -#ifdef LOGGING + + cSetupBlock::LastcChannel=(cChannel*)channel; + + + + #ifdef LOGGING dsyslog("plugin-block: new EPG title detected: '%s' - comparing with '%s'",title, cEventBlock::LastTitle); -#endif + #endif cEventBlock::LastTitle=(char*)title; if (!EventsBlock.Acceptable(title)) { - isyslog("plugin-block: channel %d blocked", channelnumber); - cControl::Launch(new cControlBlock(channel, present, follow)); + dsyslog("plugin-block: channel %i blocked", channelnumber); + + if (cOsd::IsOpen() && !cDisplayChannel::IsOpen()) + { +#ifdef LOGGING + dsyslog("plugin-block: OSD is open (%i)",channelnumber); +#endif + int lastchannel=cSetupBlock::LastAcceptableChannel; + int direction = cDevice::CurrentChannel() - lastchannel; + if (direction == 0) + direction = 1; + int switch_result=cDevice::SwitchChannel(direction); + if (switch_result) + { + cEventBlock::LastTitle="force recheck from OSD workaround"; + //in case the EPG title changes while the block message is displayed + //AND the the former and the current title are equal + //(AND maybe other conditions like the plugin is already coming from a + //blocked channel etc.) this code block is reached and only in this + //case we have to force a recheck! Maybe this is an ugly workaround + //but it seems to work... + } + else + { + if (lastchannel != 0) + { + dsyslog("plugin-block: main thread switching to last channel %i (fallback)",lastchannel); + Channels.SwitchTo(lastchannel); + } + } + } + else + { +#ifdef LOGGING + dsyslog("plugin-block: launching cControl for %i",channelnumber); +#endif + cControl::Launch(new cControlBlock(channel, present, follow)); + } + + } + else + { + cSetupBlock::LastAcceptableChannel=cDevice::CurrentChannel(); + cSetupBlock::user_direction=0; + cSetupBlock::LastcChannel=Channels.GetByNumber(cDevice::CurrentChannel()); } + } -} + + + /* bool cPluginBlock::ProcessArgs (int argc, char *argv[]) @@ -8,9 +8,6 @@ #ifndef VDR_BLOCK_COMMON_H #define VDR_BLOCK_COMMON_H -#include <stdint.h> -#include <vdr/tools.h> - #if VDRVERSNUM >= 10318 inline uint64_t time_ms() { return cTimeMs::Now(); } #endif @@ -7,19 +7,21 @@ #include "config.h" -#include <stdlib.h> -#include <string.h> cSetupBlock SetupBlock; -int cSetupBlock::LastChannel=0; +int cSetupBlock::LastAcceptableChannel=1; int cSetupBlock::DetectionMethod=0; int cSetupBlock::OkAllowed=1; -int cSetupBlock::ParentalGuidance=-1;//negative value to check later if already set by commandline argument +int cSetupBlock::ParentalGuidance=-1; //negative value to check later if already set by commandline argument +int cSetupBlock::FuzzyFallback=0; +int cSetupBlock::MessageTimeout=2; +char cSetupBlock::ReplayingName[256]={' '}; //256 corresponds to the initial EVMAXLINELENGTH in event.h; may have a more reliable implementation +cChannel* cSetupBlock::LastcChannel=NULL; +int cSetupBlock::user_direction=0; cSetupBlock::cSetupBlock(void): - HideMenuEntry(0), - MessageTimeout(2) + HideMenuEntry(0) { } @@ -31,11 +33,13 @@ bool cSetupBlock::Parse(const char *Name, const char *Value) else if (strcmp(Name, "DetectionMethod") == 0) DetectionMethod = atoi(Value); else if (strcmp(Name, "OkAllowed")==0) OkAllowed = atoi(Value); else if (strcmp(Name, "ParentalGuidance") == 0) ParentalGuidance=atoi(Value); //if cl is parsed a check has to be implemented here, to let cl value override setup.conf + else if (strcmp(Name, "FuzzyFallback")==0) FuzzyFallback=atoi(Value); else return false; if (ParentalGuidance!=-1 && ParentalGuidance!=0) //-1 if not set by cl oder setup.conf - 0 if set to disabled - other value = enabled { cSetupBlock::DetectionMethod=1; cSetupBlock::OkAllowed=0; + cSetupBlock::FuzzyFallback=0; } return true; } @@ -5,18 +5,22 @@ * */ +#include <vdr/channels.h> #ifndef VDR_BLOCK_CONFIG_H #define VDR_BLOCK_CONFIG_H class cSetupBlock { public: int HideMenuEntry; - int MessageTimeout; + static int MessageTimeout; static int DetectionMethod; - static int LastChannel; + static int LastAcceptableChannel; static int ParentalGuidance; static int OkAllowed; - + static int FuzzyFallback; + static char ReplayingName[256]; + static cChannel *LastcChannel; + static int user_direction; cSetupBlock(void); bool Parse(const char *Name, const char *Value); @@ -8,7 +8,6 @@ #include "control.h" #include "config.h" #include "common.h" - #include <vdr/remote.h> inline uint64_t BlockTimeout() { return SetupBlock.MessageTimeout * 1000; } @@ -31,11 +30,17 @@ cControlBlock::cControlBlock(const cChannel *Channel, const cEvent *Present, con needsFastResponse = true; #endif - cRemote::Put(kBack,true); //Hide OSD new version + cRemote::Put(kBack,true); //Hide OSD new version +#ifdef LOGGING + dsyslog("plugin-block: constructor cControl for %i",cDevice::CurrentChannel()); +#endif } cControlBlock::~cControlBlock() -{ +{ +#ifdef LOGGING + dsyslog("plugin-block: destructor cControl for %i",cDevice::CurrentChannel()); +#endif if (mOsd != NULL) delete mOsd; if (mRequested) @@ -43,27 +48,35 @@ cControlBlock::~cControlBlock() #ifdef LOGGING dsyslog("plugin-block: userint user requested to watch blocked channel"); #endif - //if (mChannel!=0) + if (mChannel != NULL) { cDevice::PrimaryDevice()->SwitchChannel(mChannel, true); + cSetupBlock::LastAcceptableChannel=mChannel->Number(); } else { - //don't know if this is necessary - just taken from plugin taste - //seems that mChannel cannot be 0 because it is an object reference - //changed that to NULL dsyslog("plugin-block: userint Cannot switch - channel unknown!"); } mRequested=false; } if (mSwitch) { - int lastchannel=cSetupBlock::LastChannel; + int lastchannel=cSetupBlock::LastAcceptableChannel; // possibly first or last available channel, fall back to old channel if (direction == 0) - direction = 1; + { + if (cSetupBlock::user_direction!=0) + { + direction=cSetupBlock::user_direction; + } + else + { + direction = 1; //TODO could there be another way to switch somewhere if directions are 0? + } + } + if (!cDevice::SwitchChannel(direction) && (lastchannel != 0)) Channels.SwitchTo(lastchannel); @@ -85,9 +98,6 @@ void cControlBlock::Show(void) eOSState cControlBlock::ProcessKey(eKeys Key) { -#ifdef LOGGING - dsyslog("plugin-block: userint cControlBlock::ProcessKey(%d) this = %p", Key, this); -#endif switch (Key) { @@ -114,17 +124,19 @@ eOSState cControlBlock::ProcessKey(eKeys Key) return osContinue; case kNone: -#ifdef LOGGING -dsyslog("plugin-block: userint Processing kNone (no user interaction)"); -#endif if (mStart == 0) { Show(); } - else if (time_ms() - mStart > BlockTimeout()) { - direction = mChannel->Number() - cSetupBlock::LastChannel; - mSwitch = true; - return osEnd; + else if (time_ms() - mStart > BlockTimeout()) + { + #ifdef LOGGING + dsyslog("plugin-block: userint Processing kNone (no user interaction)"); + #endif + if (cSetupBlock::user_direction ==0)direction = cDevice::CurrentChannel() -cSetupBlock::LastAcceptableChannel; + else direction =0; //TODO cleanup this direction chaos (doubleset and doublechecked here and there...) + mSwitch = true; + return osEnd; } return osContinue; @@ -144,7 +156,7 @@ dsyslog("plugin-block: userint Processing up event (userrequest)"); else { mRequested=false;//TODO:necessary? as above - direction = 1; + cSetupBlock::user_direction = 1; mSwitch = true; return osEnd; } @@ -166,7 +178,7 @@ dsyslog("plugin-block: userint Processing down event (userrequest)"); else { mRequested=false;//TODO:necessary? as above - direction = -1; + cSetupBlock::user_direction = -1; mSwitch = true; return osEnd; } @@ -8,7 +8,6 @@ #ifndef VDR_BLOCK_CONTROL_H #define VDR_BLOCK_CONTROL_H -#include <stdint.h> #include <vdr/player.h> class cControlBlock : public cControl { @@ -5,10 +5,11 @@ * */ +#include <ctype.h> +#include <vdr/status.h> #include "event.h" +#include "setup.h" -#include "common.h" -#include <ctype.h> char* cEventBlock::duptolower(const char *s) { char *c = strdup(s); @@ -18,19 +19,7 @@ char* cEventBlock::duptolower(const char *s) { return c; } -char* cEventBlock::getTimeStamp() -//Attention: this one will not return the exact UNIX time! -//Some internal cast seems to blur the word length here. -//For use in the block plugin this implementation however -//suffices because it returns something in the millisecond -//range. If you want to improve please send me an email ;) -{ - char *dummy; - asprintf(&dummy, "%jd", (intmax_t)time_ms()); - return dummy; -} - -const char* cEventBlock::LastTitle="block_dummy_title3"; +const char* cEventBlock::LastTitle="just initialized"; const bool* cEventBlock::ReplayingRecording=false; cEventsBlock EventsBlock; @@ -38,7 +27,8 @@ cEventsBlock EventsBlock; cEventBlock::cEventBlock(void): mRegularExp(false), mIgnoreCase(false), - mCompiled(false) + mCompiled(false), + whitelisted(false) { strncpy(mPattern, tr("New Entry"), sizeof(mPattern)); } @@ -46,7 +36,8 @@ cEventBlock::cEventBlock(void): cEventBlock::cEventBlock(const char *Pattern): mRegularExp(false), mIgnoreCase(false), - mCompiled(false) + mCompiled(false), + whitelisted(false) { strncpy(mPattern, Pattern, sizeof(mPattern)); } @@ -62,46 +53,104 @@ cEventBlock &cEventBlock::operator=(const cEventBlock &Src) strcpy(mPattern, Src.mPattern); mRegularExp = Src.mRegularExp; mIgnoreCase = Src.mIgnoreCase; + whitelisted = Src.whitelisted; mCompiled = false; Compile(); return *this; } +/* +bool cEventBlock::operator==(const cEventBlock Src) //include whitelisting? +{ + bool b1=(strcmp(duptolower(mPattern),duptolower(Src.mPattern))==0); + bool b2=(mRegularExp==Src.mRegularExp); + bool b3=(mIgnoreCase==Src.mIgnoreCase); + return b1&&b2&&b3; +} +*/ + cEventBlock::~cEventBlock() { if (mRegularExp) regfree(&mExpression); } -bool cEventBlock::Acceptable(const char *Event) const -{ + +bool cEventBlock::doesMatch(const char *Event) const +{//in fact here we only check if the current event has any match in the list + //of course Event is examined according to the rules defined in the blacklist if (mRegularExp) - return regexec(&mExpression, Event, 0, NULL, 0) != 0; - else if (mIgnoreCase) { + return !(regexec(&mExpression, Event, 0, NULL, 0) != 0); + if (strlen(mPattern)==0) //workaround for empty patterns + { + return (strlen(Event)==0); + } + if (mIgnoreCase) + { char *ev = cEventBlock::duptolower(Event); char *pa = cEventBlock::duptolower(mPattern); printf("check for %s in %s\n", pa, ev); bool res = strstr(ev, pa) == NULL; free(ev); free(pa); - return res; + return !res; } else - return strstr(Event, mPattern) == NULL; + return !(strstr(Event, mPattern) == NULL); } -bool cEventBlock::Parse(char *s) { - char *patternbuf = NULL; - int fields = sscanf(s, "%d:%d:%a[^\n]", &mRegularExp, &mIgnoreCase, &patternbuf); - - if (fields == 3) { - strncpy(mPattern, skipspace(stripspace(patternbuf)), sizeof(mPattern)); - free(patternbuf); - } else { // backward compatibility - strncpy(mPattern, skipspace(stripspace(s)), sizeof(mPattern)); - mRegularExp = false; - mIgnoreCase = false; - } - - return Compile(); +bool cEventBlock::Parse(char *s) +{ + char *patternbuf=NULL; + int fields=sscanf(s,"%d:%d:%a[^\n]", &mRegularExp, &mIgnoreCase, &patternbuf); + + if (fields==3) + { + strncpy(mPattern,patternbuf,sizeof(mPattern)); + char c=NULL; + int fields2=0; + + if (strcmp(patternbuf,"-:")==0)//workaround if pattern empty + { + fields2=2; + c='-'; + patternbuf=(char*)""; + } + else + { + if (strcmp(patternbuf,"+:")==0) + { + fields2=2; + c='+'; + patternbuf=(char*)""; + } //end of workaround + else + { + free(patternbuf); //normal entry handling + fields2=sscanf(mPattern,"%1c:%a[^\n]",&c,&patternbuf); + } + } + + if (fields2==2) + { + if(c=='+') + { + whitelisted=true; + } + else whitelisted=false; + strncpy(mPattern,skipspace(stripspace(patternbuf)),sizeof(mPattern)); + } + else + { + whitelisted=false; + } + } + else + { // old taste backward compatibility + strncpy(mPattern, skipspace(stripspace(s)), sizeof(mPattern)); + mRegularExp = false; + mIgnoreCase = false; + whitelisted = false; + } + return Compile(); } bool cEventBlock::Compile(void) { @@ -117,27 +166,191 @@ bool cEventBlock::Compile(void) { } bool cEventBlock::Save(FILE *f) { - return fprintf(f, "%d:%d:%s\n", mRegularExp, mIgnoreCase, mPattern) > 0; + char c='c'; + if (whitelisted) c='+'; + else c='-'; + return fprintf(f, "%d:%d:%c:%s\n", mRegularExp, mIgnoreCase, c, mPattern) > 0; } -bool cEventsBlock::Acceptable(const char *Event) { - const cEventBlock *event = First(); - while (event != NULL) { - if (!event->Acceptable(Event)) - return false; - event = Next(event); + +bool cEventsBlock::Acceptable(const char *src) +{ + cVector<cEventBlock*> temp_vec (5); + cEventBlock stringmatch=*(new cEventBlock("nostringmatch")); + + ListMatches(src,&temp_vec,stringmatch); + if(strcmp(stringmatch.Pattern(),"nostringmatch")!=0) + { +#ifdef LOGGING + dsyslog("plugin-block: exact string match found %s: ",stringmatch.Pattern()); +#endif + if (stringmatch.isWhitelisted()) + { +#ifdef LOGGING + dsyslog("plugin-block: string match entry is whitelisted - returning acceptable"); +#endif + cSetupBlock::LastAcceptableChannel=cDevice::CurrentChannel(); + return true; } +#ifdef LOGGING + dsyslog("plugin-block: string match entry is not whitelisted - returning not acceptable"); +#endif + return false; + } + + int vec_size=temp_vec.Size(); + if (vec_size<1) + { +#ifdef LOGGING + dsyslog("plugin-block: no matching pattern found at all - returning acceptable"); +#endif + cSetupBlock::LastAcceptableChannel=cDevice::CurrentChannel(); return true; + } + + bool b=temp_vec.At(0)->isWhitelisted(); + int count=1; + for(;count<vec_size;count++) + { + if (temp_vec.At(count)->isWhitelisted()!=b) + { +#ifdef LOGGING + dsyslog("plugin-block: Contradictory rules detected - returning fuzzy fallback: %d",cSetupBlock::FuzzyFallback); +#endif + b=cSetupBlock::FuzzyFallback; + if (b) cSetupBlock::LastAcceptableChannel=cDevice::CurrentChannel(); + return b; + } + } +#ifdef LOGGING + dsyslog("plugin-block: Acceptable returning: %d",b); +#endif + if (b) cSetupBlock::LastAcceptableChannel=cDevice::CurrentChannel(); + return b; } + + cEventsBlock &cEventsBlock::operator=(const cEventsBlock &Source) { cList<cEventBlock>::Clear(); const cEventBlock *event = Source.First(); while (event != NULL) { - printf("transfering %p\n", event); + printf("transferring %p\n", event); Add(new cEventBlock(*event)); event = Source.Next(event); } return *this; } + +void cEventsBlock::ListMatches(const char *title, cVector <cEventBlock*> *match_vec, cEventBlock &stringmatch) +{ + cEventBlock *event = First(); + char* temp_title=strdup(title); + char* temp_pattern=NULL; + while (event != NULL) { + if (event->doesMatch(title)) //doesMatch examines if there is a match according to all properties of the blacklist entry + { + #ifdef LOGGING + char *condition=(char*)(event->isWhitelisted() ? "positive" : "negative"); + dsyslog("plugin-block: Matching rule detected - Pattern: '%s' (%s)",event->Pattern(),condition); + #endif + match_vec->Append(event); //put match in the vector; of course there could be more than one match + //lets say you would block everything containing the word 'Judge' + //but 'Judge Dredd' also has an explicit entry + //in case Judge Dredd is the current show then both entries would match + //therefore it is necessary to do further analysis of the type of the matches + //or the according rules and priorities respectively + + if (event->IgnoreCase())//now we check if there the current match is also a stringmatching entry + //first check if ignore case is set + //if so replace the strings to be compared by their lower case pendants + //so next we only have to do one comparison + { + temp_title=cEventBlock::duptolower(temp_title); + temp_pattern=cEventBlock::duptolower(event->Pattern()); + } + else + { + temp_pattern=(char*)event->Pattern(); + } + if (strcmp(temp_title,temp_pattern)==0) //check for stringmatch + { +#ifdef LOGGING + dsyslog("plugin-block: ListMatches: stringmatch found '%s'",event->Pattern()); +#endif + stringmatch=*event; + } + } + event = Next(event); + } +} + +void cEventsBlock::ListMatches(const char *title, cVector <cEventBlock*> *match_vec) +{ + cEventBlock *event = First(); + while (event != NULL) { + if (event->doesMatch(title)) + { + match_vec->Append(event); + } + event = Next(event); + } +} + + +cEventBlock* cEventsBlock::hasStringMatch(const char* src, bool ignorecase) +{ + //TODO check if there is a better way to check for matches and stringmatches + //which avoids redundant walks through the blacklist + cEventBlock *event_ptr=First(); + char *low_src=cEventBlock::duptolower(src); + while (event_ptr!=NULL) + { + if (event_ptr->IgnoreCase() || ignorecase) + { + char *low_pattern=cEventBlock::duptolower(event_ptr->Pattern()); + if (strcmp(low_src,low_pattern)==0) + { + return event_ptr; + } + } + else + { + if (strcmp(src,event_ptr->Pattern())==0) + { + return event_ptr; + } + } + event_ptr=Next(event_ptr); + } + return NULL; +} + + +int cEventsBlock::getIndexOf(cEventBlock *src) +{ + //TODO make this a recursive method taking a list pointer and lets begin search in the middle of the list + //(middle->Previous() and middle->Next()) + //find out if the first char of Pattern is less or higher than src.char etc + //once the first char of src matches begin search there straight forward + //this might speedup setting cursor to the right position (New entry) in the OSD + //NO: it turned out that the Get method of cListBase will have a serious impact on this solution + //maybe a major rewrite and/or use of STL implementations of lists or vectors etc would be a better alternative + + cEventBlock* listptr=First(); + int list_count=0; + const char* src_pattern=src->Pattern(); + + while(listptr!=NULL) + { + if (strcmp(src_pattern,listptr->Pattern())==0) + { + return list_count; + } + list_count+=1; + listptr=Next(listptr); + } + return -1; +} +
\ No newline at end of file @@ -8,13 +8,9 @@ #ifndef VDR_BLOCK_EVENT_H #define VDR_BLOCK_EVENT_H -#include <sys/types.h> #include <regex.h> - -#include <vdr/tools.h> #include <vdr/config.h> - #define EVLINELENGTH 256 class cEventBlock : public cListObject { @@ -25,7 +21,8 @@ private: int mRegularExp; int mIgnoreCase; bool mCompiled; - + int whitelisted; + regex_t mExpression; public: @@ -35,18 +32,23 @@ public: ~cEventBlock(); cEventBlock &operator=(const cEventBlock &Src); + bool operator==(const cEventBlock Src); + - bool Acceptable(const char *Event) const ; + bool doesMatch(const char *Event) const ; + const int isWhitelisted(void) const {return whitelisted;} + void setWhitelisted(const bool b) {whitelisted=b;} + bool IgnoreCase(void) const {return mIgnoreCase;} + void setIgnoreCase(const bool b) {mIgnoreCase=b;} bool Parse(char *s); bool Compile(void); bool Save(FILE *f); static const char *LastTitle; - static const bool *ReplayingRecording; + static const bool *ReplayingRecording; + static char *duptolower(const char*); -// static char *getTimeStamp(){ char *dummy; asprintf(&dummy, "%jd", (intmax_t)time_ms()); return dummy; }; - static char *getTimeStamp(); const char *Pattern(void) const { return mPattern; } @@ -55,13 +57,20 @@ public: cEventBlock* rhs=(cEventBlock*)&src; char* l=cEventBlock::duptolower(mPattern); char* r=cEventBlock::duptolower(rhs->mPattern); - return strcmp(l,r); } + return strcmp(l,r); }//TODO check if the code relies on this because in fact we have to return !strcmp(r,l) here!!! }; class cEventsBlock : public cConfig<cEventBlock> { +private: +// int recursive_pos_seek (char *pattern, int start); + public: bool Acceptable(const char *Event); cEventsBlock &operator=(const cEventsBlock &Source); + void ListMatches (const char *src, cVector <cEventBlock*> *match_vec, cEventBlock &stringmatch); + void ListMatches (const char *src, cVector <cEventBlock*> *match_vec); + cEventBlock* hasStringMatch(const char* src, bool ignorecase=false); + int getIndexOf(cEventBlock *Src); }; extern cEventsBlock EventsBlock; @@ -35,7 +35,7 @@ const tI18nPhrase Phrases[] = { { "(De)Block broadcast", "Sendung (ent)sperren", "", - "", + "(S)Blocca trasmissione", "", "", "", @@ -60,7 +60,7 @@ const tI18nPhrase Phrases[] = { { "Block unwanted shows by EPG title", "Sendung/EPG-Titel sperren", "", - "", + "Blocca i programmi non desiderati tramite i titoli EPG", "", "", "", @@ -85,7 +85,7 @@ const tI18nPhrase Phrases[] = { { "Permission denied!", "Aktion nicht erlaubt!", "", - "", + "Permesso negato!", "", "", "", @@ -110,7 +110,7 @@ const tI18nPhrase Phrases[] = { { "Current show blocked!", "Aktuelle Sendung gesperrt!", "", - "", + "Programma attuale bloccato!", "", "", "", @@ -135,7 +135,7 @@ const tI18nPhrase Phrases[] = { { "New Entry", "Neuer Eintrag", "", - "", + "Nuovo valore", "", "", "", @@ -160,7 +160,7 @@ const tI18nPhrase Phrases[] = { { "Hide Mainmenu Entry", "Hauptmenüeintrag verstecken", "", - "", + "Nascondi voce menu principale", "", "", "", @@ -185,7 +185,7 @@ const tI18nPhrase Phrases[] = { { "Detection Method", "Methode", "", - "", + "Metodo rilevamento", "", "", "", @@ -210,7 +210,7 @@ const tI18nPhrase Phrases[] = { { "Ok deblocks temporarily", "Ok entsperrt temporär", "", - "", + "Permetti sblocchi temporanei", "", "", "", @@ -235,7 +235,7 @@ const tI18nPhrase Phrases[] = { { "On Switch", "Beim Umschalten", "", - "", + "Al cambio canale", "", "", "", @@ -260,7 +260,7 @@ const tI18nPhrase Phrases[] = { { "Channel EPG", "Kanal EPG", "", - "", + "Canale EPG", "", "", "", @@ -285,7 +285,7 @@ const tI18nPhrase Phrases[] = { { "Edit", "Editieren", "", - "", + "Modificare",//translation guessed from dict.leo.org "", "", "", @@ -310,7 +310,7 @@ const tI18nPhrase Phrases[] = { { "Delete", "Löschen", "", - "", + "Eliminare",//translation guessed from below ;) "", "", "", @@ -332,10 +332,10 @@ const tI18nPhrase Phrases[] = { "", #endif }, - { "New", + { "New", "Neu", "", - "", + "Nuovo",//translation guessed from dict.leo.org "", "", "", @@ -360,7 +360,7 @@ const tI18nPhrase Phrases[] = { { "Delete keyword?", "Schlagwort löschen?", "", - "", + "Eliminare parola chiave?", "", "", "", @@ -385,7 +385,7 @@ const tI18nPhrase Phrases[] = { { "Pattern", "Suchmuster", "", - "", + "Termine ricerca", "", "", "", @@ -407,10 +407,10 @@ const tI18nPhrase Phrases[] = { "", #endif }, - { "--- Keywords -------------------------------------------------------------------", + { "--- Keywords -------------------------------------------------------------------", "--- Schlagworte ----------------------------------------------------------------", "", - "", + "--- Parole chiave---------------------------------------------------------------", "", "", "", @@ -435,7 +435,7 @@ const tI18nPhrase Phrases[] = { { "Regular Expression", "Regulärer Ausdruck", "", - "", + "Espressione regolare", "", "", "", @@ -460,7 +460,7 @@ const tI18nPhrase Phrases[] = { { "Ignore Case", "Groß/Kleinschreibung ignorieren", "", - "", + "Ignora maiuscole/minuscole", "", "", "", @@ -485,7 +485,7 @@ const tI18nPhrase Phrases[] = { { "Malformed regular expression!", "Ungültiger regulärer Ausdruck!", "", - "", + "Espressione regolare mal costruita!", "", "", "", @@ -507,10 +507,110 @@ const tI18nPhrase Phrases[] = { "", #endif }, - { "Message Timeout [s]", + { "Message Timeout [s]", "Wartezeit bis Umschalten [s]", "", + "",//maybe someone could help out? + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "Fuzzy fallback", + "Unschärfepriorität", + "", + "",//maybe someone could help out? + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "black", + "gesperrt", + "", + "",//maybe someone could help out? + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "white", + "nicht gesperrt", + "", + "",//maybe someone could help out? + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +#if VDRVERSNUM >= 10313 + "", +#endif +#if VDRVERSNUM >= 10316 + "", +#endif + }, + { "Please edit duplicate instead", + "Bitte vorhandenen Eintrag editieren", "", + "",//maybe someone could help out? "", "", "", diff --git a/po/de_DE.po b/po/de_DE.po index da05da3..434a990 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.5.7\n" "Report-Msgid-Bugs-To: <vdrportal_midas at gmx dot de>\n" -"POT-Creation-Date: 2010-08-03 05:23+0200\n" -"PO-Revision-Date: 2010-08-03 05:23+0200\n" +"POT-Creation-Date: 2010-11-05 00:55+0100\n" +"PO-Revision-Date: 2010-11-05 00:53+0100\n" "Last-Translator: Klaus Schmidinger <kls@cadsoft.de>\n" "Language-Team: <vdr@linuxtv.org>\n" "MIME-Version: 1.0\n" @@ -21,15 +21,12 @@ msgstr "Sendung/EPG-Titel sperren" msgid "(De)Block broadcast" msgstr "Sendung (ent)sperren" -msgid "Delete keyword?" -msgstr "Schlagwort löschen?" +msgid "Permission denied!" +msgstr "Aktion nicht erlaubt!" msgid "Current show blocked!" msgstr "Aktuelle Sendung gesperrt!" -msgid "Permission denied!" -msgstr "Aktion nicht erlaubt!" - msgid "New Entry" msgstr "Neuer Eintrag" @@ -45,15 +42,27 @@ msgstr "Beim Umschalten" msgid "Channel EPG" msgstr "Kanal EPG" +msgid "black" +msgstr "gesperrt" + +msgid "white" +msgstr "nicht gesperrt" + msgid "Detection Method" msgstr "Methode" msgid "Ok deblocks temporarily" msgstr "Ok entsperrt temporär" +msgid "Fuzzy fallback" +msgstr "Unschärfepriorität" + msgid "--- Keywords -------------------------------------------------------------------" msgstr "--- Schlagworte ----------------------------------------------------------------" +msgid "Delete keyword?" +msgstr "Schlagwort löschen?" + msgid "Pattern" msgstr "Suchmuster" @@ -63,5 +72,11 @@ msgstr "Regulärer Ausdruck" msgid "Ignore Case" msgstr "Groß/Kleinschreibung ignorieren" +msgid "Whitelist" +msgstr "" + msgid "Malformed regular expression!" msgstr "Ungültiger regulärer Ausdruck!" + +msgid "Please edit duplicate instead" +msgstr "Bitte vorhandenen Eintrag editieren" diff --git a/po/it_IT.po b/po/it_IT.po new file mode 100644 index 0000000..cf7da03 --- /dev/null +++ b/po/it_IT.po @@ -0,0 +1,84 @@ +# VDR plugin language source file. +# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> +# This file is distributed under the same license as the VDR package. +# Alberto Carraro <bertocar@tin.it>, 2001 +# Antonio Ospite <ospite@studenti.unina.it>, 2003 +# Sean Carlos <seanc@libero.it>, 2005 +# +msgid "" +msgstr "" +"Project-Id-Version: VDR 1.5.7\n" +"Report-Msgid-Bugs-To: <vdrportal_midas at gmx dot de>\n" +"POT-Creation-Date: 2010-11-05 00:55+0100\n" +"PO-Revision-Date: 2010-11-05 00:53+0100\n" +"Last-Translator: Sean Carlos <seanc@libero.it>\n" +"Language-Team: <vdr@linuxtv.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Block unwanted shows by EPG title" +msgstr "Blocca i programmi non desiderati tramite i titoli EPG" + +msgid "(De)Block broadcast" +msgstr "(S)Blocca trasmissione" + +msgid "Permission denied!" +msgstr "Permesso negato!" + +msgid "Current show blocked!" +msgstr "Programma attuale bloccato!" + +msgid "New Entry" +msgstr "Nuovo valore" + +msgid "Hide Mainmenu Entry" +msgstr "Nascondi voce menu principale" + +msgid "Message Timeout [s]" +msgstr "" + +msgid "On Switch" +msgstr "Al cambio canale" + +msgid "Channel EPG" +msgstr "Canale EPG" + +msgid "black" +msgstr "" + +msgid "white" +msgstr "" + +msgid "Detection Method" +msgstr "Metodo rilevamento" + +msgid "Ok deblocks temporarily" +msgstr "Permetti sblocchi temporanei" + +msgid "Fuzzy fallback" +msgstr "" + +msgid "--- Keywords -------------------------------------------------------------------" +msgstr "--- Parole chiave---------------------------------------------------------------" + +msgid "Delete keyword?" +msgstr "Eliminare parola chiave?" + +msgid "Pattern" +msgstr "Termine ricerca" + +msgid "Regular Expression" +msgstr "Espressione regolare" + +msgid "Ignore Case" +msgstr "Ignora maiuscole/minuscole" + +msgid "Whitelist" +msgstr "" + +msgid "Malformed regular expression!" +msgstr "Espressione regolare mal costruita!" + +msgid "Please edit duplicate instead" +msgstr "" @@ -28,17 +28,23 @@ void cMenuSetupBlock::Set(void) { DetectionMethods[0] = tr("On Switch"); DetectionMethods[1] = tr("Channel EPG"); + + FuzzyFallsback[0] = tr("black"); + FuzzyFallsback[1] = tr("white"); cMenuEditStraItem *methoditem = new cMenuEditStraItem(tr("Detection Method"), &mSetupData.DetectionMethod, 2, DetectionMethods); cMenuEditBoolItem *okitem = new cMenuEditBoolItem(tr("Ok deblocks temporarily"), &mSetupData.OkAllowed); + cMenuEditStraItem *whitelistitem = new cMenuEditStraItem(tr("Fuzzy fallback"), &mSetupData.FuzzyFallback, 2, FuzzyFallsback); if(cSetupBlock::ParentalGuidance==1) { methoditem->SetSelectable(false); okitem->SetSelectable(false); + whitelistitem->SetSelectable(false); } Add(methoditem); Add(okitem); + Add(whitelistitem); item = new cOsdItem(""); item->SetSelectable(false); @@ -48,14 +54,25 @@ void cMenuSetupBlock::Set(void) { item->SetSelectable(false); Add(item); -#define NONKEYWORDITEMS 6 +#define NONKEYWORDITEMS 7 int index = 0; cEventBlock *event = mEventsData.First(); - while (event != NULL) { - Add(new cOsdItem(event->Pattern())); - event = mEventsData.Next(event); - ++index; + char* entry=NULL; + char listtype=NULL; + while (event != NULL) + {//TODO? maybe slow as the string has to be constructed for every entry and + //the method is called (?) every main thread of vdr (especially in case of a long list...) + //for now let's assume everyone has a cpu that's fast enough + //little workaround could be to take a fixed (EVMAXLINELENGTH+2) string buffer and use + //sprintf or something instead + //of course the implementation of block analysis in an extra thread would also relax this + if (event->isWhitelisted()) listtype='+'; + else listtype='-'; + asprintf(&entry,"%c:%s",listtype,event->Pattern()); + Add(new cOsdItem(entry)); + event = mEventsData.Next(event); + ++index; } SetCurrent(Get(current)); @@ -67,14 +84,25 @@ void cMenuSetupBlock::SetHelpKeys(void) { const char *red = NULL; const char *yellow = NULL; + const char *blue = NULL; printf("sethelpkeys, current = %d\n", Current()); - if (Current() >= NONKEYWORDITEMS) { - red = trVDR("Button$Edit"); - yellow = trVDR("Button$Delete"); + if (Current() >= NONKEYWORDITEMS) + { + red = trVDR("Button$Edit"); + if (cSetupBlock::ParentalGuidance!=1) + { + yellow = trVDR("Button$Delete"); + blue = trVDR("Button$+/-"); + } } - SetHelp(red, trVDR("Button$New"), yellow, NULL); + if(cSetupBlock::ParentalGuidance!=1) + { + SetHelp(red, trVDR("Button$New"), yellow, blue); + } + else + SetHelp(red,trVDR("Button$New")); } void cMenuSetupBlock::Store(void) @@ -88,6 +116,8 @@ void cMenuSetupBlock::Store(void) SetupStore("MessageTimeout", SetupBlock.MessageTimeout); SetupStore("DetectionMethod", SetupBlock.DetectionMethod); SetupStore("OkAllowed", SetupBlock.OkAllowed); + SetupStore("FuzzyFallback", SetupBlock.FuzzyFallback); + cEventBlock::LastTitle=(char*)"force recheck from setup"; } eOSState cMenuSetupBlock::Edit(void) @@ -95,9 +125,22 @@ eOSState cMenuSetupBlock::Edit(void) if (HasSubMenu() || Current() < NONKEYWORDITEMS) return osContinue; + cEventBlock *event = mEventsData.Get(Current() - NONKEYWORDITEMS); if (event != NULL) - return AddSubMenu(new cMenuSetupEditBlock(event)); + { + if (cSetupBlock::ParentalGuidance==1 && strcmp(event->Pattern(),tr("New Entry"))!=0) + { + Skins.Message(mtError, tr("Permission denied!")); + dsyslog("plugin-block: Parental guidance detected attempt to edit another than a new entry. Permission denied!"); + return osContinue; + } + eOSState retval= AddSubMenu(new cMenuSetupEditBlock(event)); + EventsBlock = mEventsData; + EventsBlock.Sort(); + EventsBlock.Save(); + return retval; + } return osContinue; } @@ -105,12 +148,37 @@ eOSState cMenuSetupBlock::New(void) { if (HasSubMenu()) return osContinue; - - mEventsData.Add(new cEventBlock()); + + cEventBlock* dummy1=new cEventBlock(); + if(mEventsData.hasStringMatch(dummy1->Pattern(),true)!=NULL) + { + Set(); + SetCurrent(Get (NONKEYWORDITEMS + mEventsData.getIndexOf(dummy1))); + delete(dummy1); + return osContinue; + } + mEventsData.Add(dummy1); Set(); + SetCurrent(Get(NONKEYWORDITEMS + mEventsData.getIndexOf(dummy1))); return osContinue; } +eOSState cMenuSetupBlock::SetListProperty(void) +{ + if (HasSubMenu() || Current() < NONKEYWORDITEMS) + return osContinue; + + cEventBlock *event = mEventsData.Get(Current() - NONKEYWORDITEMS); + if (event != NULL) + { + event->setWhitelisted(!(event->isWhitelisted())); + EventsBlock = mEventsData; + EventsBlock.Save(); + } + return osContinue; +} + + eOSState cMenuSetupBlock::Delete(void) { if (HasSubMenu() || Current() < NONKEYWORDITEMS) @@ -119,41 +187,53 @@ eOSState cMenuSetupBlock::Delete(void) cEventBlock *event = mEventsData.Get(Current() - NONKEYWORDITEMS); if (event != NULL) { if (Interface->Confirm(tr("Delete keyword?"))) - mEventsData.Del(event); + { + mEventsData.Del(event,true); + EventsBlock = mEventsData; + EventsBlock.Save(); + + } } Set(); return osContinue; } -eOSState cMenuSetupBlock::ProcessKey(eKeys Key) { - bool hadSubMenu = HasSubMenu(); - eOSState state = cMenuSetupPage::ProcessKey(Key); +eOSState cMenuSetupBlock::ProcessKey(eKeys Key) +{ + bool hadSubMenu = HasSubMenu(); + eOSState state = cMenuSetupPage::ProcessKey(Key); - if (hadSubMenu && !HasSubMenu()) { - Set(); - return state; - } + if (hadSubMenu && !HasSubMenu()) + { + Set(); + return state; + } - switch (state) { - case osUnknown: // normal key handling - switch (Key) { - case kRed: if (mSetupData.ParentalGuidance!=1) return Edit(); - break; - case kGreen: if (mSetupData.ParentalGuidance!=1) return New(); - break; - case kYellow: if (mSetupData.ParentalGuidance!=1) return Delete(); - break; - default: - break; + switch (state) + { + case osUnknown: // normal key handling + switch (Key) + { + case kRed: return Edit(); + break; + case kGreen: return New(); + break; + case kYellow: if (mSetupData.ParentalGuidance!=1) return Delete(); + break; + case kBlue: if (mSetupData.ParentalGuidance!=1) return SetListProperty(); + + default: + break; } - break; - default: break; + + default: + break; } - if (!HasSubMenu()) - Set(); + if (!HasSubMenu()) + Set(); return state; } @@ -165,12 +245,16 @@ cMenuSetupEditBlock::cMenuSetupEditBlock(cEventBlock *Event): mEvent(Event), mData(*Event) { - char buf[80]; - snprintf(buf, sizeof(buf), "%s - %s '%s'", trVDR("Setup"), trVDR("Plugin"), "block"); - SetTitle(buf); - Add(new cMenuEditStrItem(tr("Pattern"), mData.mPattern, sizeof(mData.mPattern), tr(ALLOWEDCHARS))); - Add(new cMenuEditBoolItem(tr("Regular Expression"), &mData.mRegularExp)); - Add(new cMenuEditBoolItem(tr("Ignore Case"), &mData.mIgnoreCase)); + char buf[80]; + snprintf(buf, sizeof(buf), "%s - %s '%s'", trVDR("Setup"), trVDR("Plugin"), "block"); + SetTitle(buf); + Add(new cMenuEditStrItem(tr("Pattern"), mData.mPattern, sizeof(mData.mPattern), tr(ALLOWEDCHARS))); + Add(new cMenuEditBoolItem(tr("Regular Expression"), &mData.mRegularExp)); + if (cSetupBlock::ParentalGuidance!=1) + { + Add(new cMenuEditBoolItem(tr("Ignore Case"), &mData.mIgnoreCase)); + Add(new cMenuEditBoolItem(tr("Whitelist"), &mData.whitelisted)); + } } eOSState cMenuSetupEditBlock::ProcessKey(eKeys Key) @@ -180,19 +264,30 @@ eOSState cMenuSetupEditBlock::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { case kOk: - if (!mData.Compile()) { - Skins.Message(mtError, tr("Malformed regular expression!")); - state = osContinue; - } else { - *mEvent = mData; - state = osBack; + if (!mData.Compile()) + { + Skins.Message(mtError, tr("Malformed regular expression!")); + state = osContinue; + } + else + { + if(EventsBlock.hasStringMatch(mData.Pattern(),true)!=NULL && (strcmp(mEvent->Pattern(),mData.Pattern())!=0)) + { + Skins.Message(mtError, tr("Please edit duplicate instead")); + state=osBack; + } + else + { + *mEvent = mData; + state = osBack; + + } } - break; + break; default: break; } } - EventsBlock.Sort(); return state; } @@ -18,6 +18,7 @@ private: cEventsBlock mEventsData; cSetupBlock mSetupData; const char *DetectionMethods[2]; + const char *FuzzyFallsback[2]; protected: virtual void Store(void); @@ -29,6 +30,7 @@ protected: eOSState Edit(void); eOSState New(void); eOSState Delete(void); + eOSState SetListProperty(void); public: cMenuSetupBlock(); @@ -5,8 +5,6 @@ * */ -#include <vdr/channels.h> - #include "status.h" #include "control.h" #include "event.h" @@ -24,20 +22,19 @@ void cStatusBlock::ChannelSwitch(const cDevice *Device, int ChannelNumber) int device_number=Device->DeviceNumber(); #endif - if (cSetupBlock::LastChannel==0) + if (cSetupBlock::LastAcceptableChannel==0) { #ifdef LOGGING - dsyslog("plugin-block: ChannelSwitch returned because LastChannel=0"); + dsyslog("plugin-block: ChannelSwitch returned because LastAcceptableChannel=0"); #endif - cSetupBlock::LastChannel=current_channel; + cSetupBlock::LastAcceptableChannel=current_channel; return; } if (ChannelNumber==0) { #ifdef LOGGING - dsyslog("plugin-block: ChannelSwitch: device switching - setting LastChannel to %d",current_channel); -#endif - cSetupBlock::LastChannel=current_channel; + dsyslog("plugin-block: ChannelSwitch returned because ChannelNumber=0 (switch in progress)."); +#endif return; //Switch in progress; } @@ -48,33 +45,37 @@ void cStatusBlock::ChannelSwitch(const cDevice *Device, int ChannelNumber) for (int ii=0;ii<cDevice::NumDevices();ii++) { cDevice* tmpdev=cDevice::GetDevice(ii); - dsyslog("plugin-block: cDevice %d replaying: %d, transferring %d",ii,tmpdev->Replaying(),tmpdev->Transferring()); + dsyslog("plugin-block: cDevice %d replaying: %d, transferring %d, hasprogramme %d",ii,tmpdev->Replaying(),tmpdev->Transferring(),tmpdev->HasProgramme()); } #endif - if (cSetupBlock::DetectionMethod!=0) + if (Device->DeviceNumber()!=cDevice::PrimaryDevice()->DeviceNumber()) { #ifdef LOGGING - dsyslog("plugin-block: ChannelSwitch returned because other detection method active"); + dsyslog("plugin-block: Did nothing cause ChannelSwitch not on active livedevice."); #endif return; } - if (Device->DeviceNumber()!=cDevice::PrimaryDevice()->DeviceNumber()) + + if (ChannelNumber!=current_channel) { #ifdef LOGGING - dsyslog("plugin-block: Did nothing cause ChannelSwitch not on active livedevice."); + dsyslog("plugin-block: Did nothing because ChannelNumber!=CurrentChannel (switch still in progress)"); #endif - return; + + return; } - if (ChannelNumber!=current_channel) + if (cSetupBlock::DetectionMethod!=0) { #ifdef LOGGING - dsyslog("plugin-block: Did nothing because ChannelNumber!=CurrentChannel (switch still in progress)"); + dsyslog("plugin-block: ChannelSwitch returned because other detection method active"); #endif return; } + + if (Device->Replaying()) { @@ -119,6 +120,11 @@ void cStatusBlock::ChannelSwitch(const cDevice *Device, int ChannelNumber) dsyslog("plugin-block: channel %d blocked", ChannelNumber); cControl::Launch(new cControlBlock(channel, present, follow)); } + else + { + cSetupBlock::LastAcceptableChannel=cDevice::CurrentChannel(); + cSetupBlock::user_direction=0; + } } } @@ -130,10 +136,10 @@ void cStatusBlock::Replaying(const cControl *Control, char *replaystate; if (On) replaystate=(char*)"started"; else replaystate=(char*)"stopped"; - cEventBlock::ReplayingRecording=(bool*)On; + cEventBlock::ReplayingRecording=(bool*)On;//TODO put this one also into setup or better into the helper.c if ever implemented + if (Name!=NULL) strncpy(cSetupBlock::ReplayingName,Name,sizeof(cSetupBlock::ReplayingName)); #ifdef LOGGING - dsyslog("plugin-block: cStatusBlock: Replay: '%s' from '%s'",Name,FileName); -#endif + dsyslog("plugin-block: cStatusBlock: Replay: '%s' from '%s' %s",Name,FileName,replaystate); +#endif } -
\ No newline at end of file @@ -11,12 +11,14 @@ #include <vdr/status.h> class cStatusBlock : public cStatus { +private: protected: virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On); + public: cStatusBlock(void); }; |