summaryrefslogtreecommitdiff
path: root/pin.c
diff options
context:
space:
mode:
Diffstat (limited to 'pin.c')
-rw-r--r--pin.c882
1 files changed, 882 insertions, 0 deletions
diff --git a/pin.c b/pin.c
new file mode 100644
index 0000000..6a8ac9f
--- /dev/null
+++ b/pin.c
@@ -0,0 +1,882 @@
+/*
+ * pin.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * Date: 11.04.05 - 23.11.06
+ */
+
+//***************************************************************************
+// Includes
+//***************************************************************************
+
+#include <vdr/interface.h>
+#include <vdr/videodir.h>
+#include <vdr/menu.h>
+
+#include "pin.h"
+#include "menu.h"
+#include "setupmenu.h"
+
+//***************************************************************************
+// Pin Service
+//***************************************************************************
+
+void Translations::append(const char* in, const char* out)
+{
+ if (!in)
+ return ;
+
+ Translation* t = new Translation;
+
+ Add(t);
+
+ strncpy(t->in, in, 200);
+ t->in[200] = 0;
+ strncpy(t->out, out ? out : "", 200);
+ t->out[200] = 0;
+}
+
+const char* Translations::lookup(const char* in)
+{
+ for (Translation* p = First(); p; p = Next(p))
+ if (strcmp(p->in, in) == 0)
+ return p->out;
+
+ return 0;
+}
+
+//***************************************************************************
+// Pin
+//***************************************************************************
+//***************************************************************************
+// Object
+//***************************************************************************
+
+cPin::cPin(void)
+{
+ pinSetup = *cPinPlugin::pinCode ? no : yes; // code already configured
+
+ if (pinSetup)
+ pinTxt = tr("Setup your pin code: ");
+ else
+ pinTxt = tr("Pin Code: ");
+
+ tell(eloDebug, "Debug: pin is '%s', text = '%s'", cPinPlugin::pinCode, pinTxt);
+
+ display = 0;
+ clear();
+}
+
+cPin::~cPin()
+{
+ if (display) delete display;
+}
+
+//***************************************************************************
+// Clear
+//***************************************************************************
+
+void cPin::clear()
+{
+ *code = 0;
+ cOsd::pinValid = no;
+}
+
+//***************************************************************************
+// Show
+//***************************************************************************
+
+void cPin::Show(void)
+{
+ display = Skins.Current()->DisplayMessage();
+ display->SetMessage(mtInfo, pinTxt);
+ cStatus::MsgOsdStatusMessage(pinTxt);
+ display->Flush();
+}
+
+//***************************************************************************
+// Process Key
+//***************************************************************************
+
+eOSState cPin::ProcessKey(eKeys Key)
+{
+ char txt[50+TB];
+ int len = strlen(code);
+ eOSState state = cOsdObject::ProcessKey(Key);
+
+ if (state == osUnknown)
+ {
+ switch (Key)
+ {
+ case kBack:
+ {
+ return osEnd;
+ }
+
+ case kLeft:
+ {
+ if (len <= 0)
+ break;
+
+ len--;
+ code[len] = 0;
+ break;
+ }
+
+ case k0 ... k9:
+ {
+ if (len >= 5) // max 5 digits
+ break;
+
+ code[len++] = Key-k0+48;
+ code[len] = 0;
+ break;
+ }
+
+ case kOk:
+ {
+ cOsd::pinValid = no;
+
+ if (!pinSetup || (pinSetup && *code))
+ {
+ if (pinSetup)
+ strcpy(cPinPlugin::pinCode, code); // setup pin code
+
+ if (strcmp(code, cPinPlugin::pinCode) == 0)
+ cOsd::pinValid = yes;
+ }
+
+ state = osEnd;
+ break;
+ }
+
+ default: return state;
+ }
+
+ if (state == osEnd)
+ {
+ if (pinSetup && cOsd::pinValid)
+ {
+ (cPinPlugin::getObject())->StorePin();
+ display->SetMessage(mtInfo, tr("Pin code successfully setup"));
+ cStatus::MsgOsdStatusMessage(tr("Pin code successfully setup"));
+ display->Flush();
+ sleep(2);
+ }
+
+ if (cOsd::pinValid && cPinPlugin::autoMenuOpen)
+ {
+ cRemote::CallPlugin("pin");
+ }
+ else
+ {
+ display->SetMessage(cOsd::pinValid ? mtInfo : mtWarning,
+ cOsd::pinValid ? tr("Code accepted") : tr("Invalid Code !"));
+ cStatus::MsgOsdStatusMessage(cOsd::pinValid ? tr("Code accepted") : tr("Invalid Code !"));
+ display->Flush();
+ sleep(1);
+ }
+ }
+ else
+ {
+ int i;
+
+ strcpy(txt, pinTxt);
+
+ for (i = 0; i < len; i++)
+ txt[strlen(pinTxt)+i] = '*';
+
+ txt[strlen(pinTxt)+i] = 0;
+
+ display->SetMessage(mtInfo, txt);
+ cStatus::MsgOsdStatusMessage(txt);
+ display->Flush();
+ state = osContinue;
+ }
+ }
+
+ return state;
+}
+
+//***************************************************************************
+// PIN Plugin
+//***************************************************************************
+//***************************************************************************
+// Static Stuff
+//***************************************************************************
+
+char cPinPlugin::pinCode[] = "";
+cPinPlugin* cPinPlugin::object = 0;
+bool cPinPlugin::skipChannelSilent = no;
+bool cPinPlugin::hideProtectedMenus = no;
+bool cPinPlugin::hideProtectedPlugins = no;
+bool cPinPlugin::hideProtectedRecordings = no;
+int cPinPlugin::pinResetTime = 90 /* minutes */; // default 1,5 hour
+bool cPinPlugin::autoMenuOpen = yes;
+int cPinPlugin::autoProtectionMode = apmIntelligent;
+
+const char* cPinPlugin::autoProtectionModes[] =
+{
+ "always",
+ "intelligent",
+ "never",
+
+ 0
+};
+
+//***************************************************************************
+// Object
+//***************************************************************************
+
+cPinPlugin::cPinPlugin(void)
+ : lockedChannels(ltChannels),
+ lockedBroadcasts(ltBroadcasts),
+ lockedPlugins(ltPlugins),
+ lockedMenuItems(ltMenuItems)
+{
+ statusMonitor = 0;
+ lastAction = time(0);
+ receiver = 0;
+ cOsd::pinValid = no; // initial sperren
+}
+
+cPinPlugin::~cPinPlugin()
+{
+ if (receiver) delete receiver;
+ if (statusMonitor) delete statusMonitor;
+}
+
+//***************************************************************************
+// Store Pin Code
+//***************************************************************************
+
+void cPinPlugin::StorePin()
+{
+ SetupStore("pinCode", cPinPlugin::pinCode);
+}
+
+//***************************************************************************
+// Initialize
+//***************************************************************************
+
+bool cPinPlugin::Initialize(void)
+{
+ char* path;
+ int res;
+
+ res = asprintf(&path, "%s/%s", cPlugin::ConfigDirectory(), "pin");
+
+ if (res < 0) ; // memory problems :o
+
+ if (!DirectoryOk(path, no))
+ {
+ if (mkdir(path, 0770))
+ {
+ // cannot create the directory
+
+ tell(eloAlways, "Creating of directory '%s' failed, errno was (%d) - '%s'",
+ path, errno, strerror(errno));
+ free(path);
+
+ return true; // anyhow let vdr start
+ }
+ }
+
+ free(path);
+
+ lockedChannels.Load(AddDirectory(cPlugin::ConfigDirectory(),
+ "pin/channellocks.conf"), true, false);
+ lockedBroadcasts.Load(AddDirectory(cPlugin::ConfigDirectory(),
+ "pin/broadcastlocks.conf"), true, false);
+ lockedPlugins.Load(AddDirectory(cPlugin::ConfigDirectory(),
+ "pin/pluginlocks.conf"), true, false);
+ lockedMenuItems.Load(AddDirectory(cPlugin::ConfigDirectory(),
+ "pin/menulocks.conf"), true, false);
+
+ return true;
+}
+
+//***************************************************************************
+// Main Menu Action
+//***************************************************************************
+
+cOsdObject* cPinPlugin::MainMenuAction(void)
+{
+ initPluginList();
+
+ if (cOsd::pinValid)
+ return new cPinMenu(MAINMENUENTRY, &lockedChannels,
+ &lockedBroadcasts, &lockedPlugins,
+ &lockedMenuItems);
+
+ return new cPin();
+}
+
+//***************************************************************************
+// Start
+//***************************************************************************
+
+bool cPinPlugin::Start(void)
+{
+ statusMonitor = new cPinStatusMonitor;
+ object = this;
+
+ receiver = new MessageReceiver;
+ receiver->StartReceiver();
+
+ return true;
+}
+
+//***************************************************************************
+// Stop
+//***************************************************************************
+
+void cPinPlugin::Stop(void)
+{
+ receiver->StopReceiver();
+}
+
+//***************************************************************************
+// Setup Menu
+//***************************************************************************
+
+cMenuSetupPage* cPinPlugin::SetupMenu(void)
+{
+ if (cOsd::pinValid)
+ return new PinSetupMenu;
+
+ Skins.Message(mtInfo, tr("Please enter pin code first"));
+
+ return 0;
+}
+
+//***************************************************************************
+// Setup Parse
+//***************************************************************************
+
+bool cPinPlugin::SetupParse(const char *Name, const char *Value)
+{
+ // Pase Setup Parameters
+
+ if (!strcasecmp(Name, "pinCode"))
+ strcpy(pinCode, Value);
+ else if (!strcasecmp(Name, "skipChannelSilent"))
+ skipChannelSilent = atoi(Value);
+ else if (!strcasecmp(Name, "hideProtectedMenus"))
+ hideProtectedMenus = atoi(Value);
+ else if (!strcasecmp(Name, "hideProtectedPlugins"))
+ hideProtectedPlugins = atoi(Value);
+ else if (!strcasecmp(Name, "hideProtectedRecordings"))
+ hideProtectedRecordings = atoi(Value);
+ else if (!strcasecmp(Name, "pinResetTime"))
+ pinResetTime = atoi(Value);
+ else if (!strcasecmp(Name, "autoMenuOpen"))
+ autoMenuOpen = atoi(Value);
+ else if (!strcasecmp(Name, "autoProtectionMode"))
+ autoProtectionMode = atoi(Value);
+ else
+ return false;
+
+ return true;
+}
+
+//***************************************************************************
+// Test if Channel Protected
+//***************************************************************************
+
+int cPinPlugin::channelProtected(const char* name, long startTime)
+{
+ return lockedChannels.Locked(name, startTime);
+}
+
+//***************************************************************************
+// Test if Plugin Protected
+//***************************************************************************
+
+int cPinPlugin::pluginProtected(const char* name)
+{
+ return lockedPlugins.Locked(name);
+}
+
+//***************************************************************************
+// Test if Menu Item Protected
+//***************************************************************************
+
+int cPinPlugin::menuItemProtected(const char* text)
+{
+ return lockedMenuItems.Locked(text);
+}
+
+//***************************************************************************
+// Append Menu Item
+//***************************************************************************
+
+int cPinPlugin::menuItemAppend(const char* text)
+{
+ cLockItem* item;
+
+ if (!lockedMenuItems.FindByName(text))
+ {
+ lockedMenuItems.Add(item = new cLockItem(text));
+ item->SetActive(no);
+ }
+
+ return success;
+}
+
+//***************************************************************************
+// Test if Broadcast Protected
+//***************************************************************************
+
+int cPinPlugin::broadcastProtected(const char* title)
+{
+ return lockedBroadcasts.Locked(title);
+}
+
+//***************************************************************************
+// Check Action Time
+//***************************************************************************
+
+void cPinPlugin::checkActivity()
+{
+ time_t lNow = time(0);
+
+ if (pinResetTime > 0 && lNow > lastAction+(pinResetTime*60) && cOsd::pinValid)
+ {
+ // keine User Aktion, Kindersicherung aktivieren ..
+
+ tell(eloAlways, "Pin: Locking pin due to no user inactivity of (%ld) seconds",
+ lNow-lastAction);
+
+ cOsd::pinValid = no;
+ }
+
+ lastAction = lNow;
+}
+
+//***************************************************************************
+// Init Plugin List
+//***************************************************************************
+
+int cPinPlugin::initPluginList()
+{
+ static int initialized = no;
+
+ cPlugin* plugin;
+ int i = 0;
+ int cnt = 0;
+ cLockItem* item;
+
+ if (initialized)
+ return done;
+
+ initialized = yes;
+
+#ifdef __EXCL_PLUGINS
+ tell(eloAlways, "exclude plugins '%s' from pin protection", __EXCL_PLUGINS);
+#endif
+
+ while ((plugin = cPluginManager::GetPlugin(i)))
+ {
+ if (strcasecmp(plugin->Name(), "pin") != 0
+#ifdef __EXCL_PLUGINS
+ && !strstr(__EXCL_PLUGINS, plugin->Name())
+#endif
+ )
+ {
+ // nicht das pin plugin und keine Plugs aus der Exclude Liste
+
+ if (!(item = lockedPlugins.FindByName(plugin->Name())))
+ {
+ lockedPlugins.Add(new cLockItem(plugin->Name(), no,
+ plugin->MainMenuEntry()));
+
+ tell(eloAlways, "PIN added plugin (%d) '%s' - '%s'",
+ i, plugin->Name(), plugin->MainMenuEntry());
+
+ cnt++;
+ }
+ else
+ {
+ item->SetTitle(plugin->MainMenuEntry());
+ }
+ }
+
+ i++;
+ };
+
+ if (cnt)
+ lockedPlugins.Save();
+
+ return done;
+}
+
+//***************************************************************************
+// Channel Switch
+//***************************************************************************
+
+void cPinStatusMonitor::ChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView)
+{
+ // cChannel* channel = Channels.GetByNumber(ChannelNumber);
+}
+
+//***************************************************************************
+// User Action
+//***************************************************************************
+
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+void cPinStatusMonitor::UserAction(const eKeys key)
+#else
+void cPinStatusMonitor::UserAction(const eKeys key, const cOsdObject* Interact)
+#endif
+{
+ tell(eloDebug, "Pin: UserAction, key (%d)", key);
+
+ (cPinPlugin::getObject())->checkActivity();
+}
+
+//***************************************************************************
+// Replay Protected
+//***************************************************************************
+
+bool cPinStatusMonitor::ReplayProtected(const cRecording* Recording, const char* Name,
+ const char* Base, bool isDirectory, int menuView)
+{
+ bool fProtected;
+ struct stat ifo;
+ char* path = 0;
+ char* base = 0;
+ char* name = 0;
+ int res;
+
+ if (Base)
+ {
+ base = strdup(Base);
+ base = ExchangeChars(base, true);
+ }
+
+ if (Name)
+ {
+ name = strdup(Name);
+
+ if (isDirectory)
+ name = ExchangeChars(name, true);
+ }
+
+ tell(eloDebug, "checking protection of %s '%s%s%s'",
+ isDirectory ? "directory" : "recording",
+ isDirectory && base ? base : "",
+ isDirectory && base ? "/" : "",
+ isDirectory || !Recording ? name : Recording->Name());
+
+ if (cOsd::pinValid)
+ return false;
+
+ if (menuView && !cPinPlugin::hideProtectedRecordings)
+ return false;
+
+ if (isDirectory)
+ res = asprintf(&path, "%s%s%s/%s/%s",
+#if APIVERSNUM > 20103
+ cVideoDirectory::Name(),
+#else
+ VideoDirectory,
+#endif
+ base ? "/" : "",
+ base ? base : "",
+ name ? name : "",
+ PROTECTION_FILE);
+ else
+ res = asprintf(&path, "%s/%s",
+ Recording ? Recording->FileName() : name,
+ PROTECTION_FILE);
+
+
+ if (res < 0) ; // memory problems :o
+
+ tell(eloDebug, "checking rights, protection file is '%s'", path);
+
+ fProtected = stat(path, &ifo) == 0;
+
+ if (path) free(path);
+ if (base) free(base);
+ if (name) free(name);
+
+ if (fProtected)
+ {
+ if (!menuView)
+ Skins.Message(mtError, tr("Recording protected, enter pin code first"));
+
+ return true;
+ }
+
+ return false;
+}
+
+//***************************************************************************
+// Channel Protected
+//***************************************************************************
+
+bool cPinStatusMonitor::ChannelProtected(const cDevice *Device, const cChannel* Channel)
+{
+ char* buf;
+ const cEvent* event;
+
+ if (cOsd::pinValid)
+ return false;
+
+ if (!Channel || !Channel->Name() || Channel->GroupSep())
+ return false;
+
+ // first check channel protection
+
+ tell(eloDebug, "checking protection of channel '%s', '%s'",
+ Channel->Name(),
+ Channel->ShortName());
+
+ if ((cPinPlugin::getObject())->channelProtected(Channel->Name()))
+ {
+ int res;
+
+ tell(eloDebug, "channel %d '%s' is protected", Channel->Number(), Channel->Name());
+
+ if (cPinPlugin::skipChannelSilent)
+ return true;
+
+ res = asprintf(&buf, "%d %s - %s", Channel->Number(), Channel->Name(), tr("channel is protected"));
+ if (res < 0) ; // memory problems :o
+ Skins.Message(mtInfo, buf);
+
+ free(buf);
+
+ return true;
+ }
+
+ // get schedules lock
+
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+ LOCK_SCHEDULES_READ;
+
+ if (!(event = GetEventOf(Schedules, Channel)))
+ return false;
+#else
+ cSchedulesLock schedLock;
+ const cSchedules* schedules;
+
+ if (!(schedules = cSchedules::Schedules(schedLock)))
+ return false;
+
+ if (!(event = GetEventOf(schedules, Channel)))
+ return false;
+#endif
+
+ // second check broadcast protection
+
+ if ((cPinPlugin::getObject())->broadcastProtected(event->Title()))
+ {
+ int res;
+
+ if (cPinPlugin::skipChannelSilent)
+ return true;
+
+ tell(eloDebug, "broadcast '%s' is protected", event->Title());
+ res = asprintf(&buf, "%s - %s", event->Title(), tr("broadcast is protected"));
+ if (res < 0) ; // memory problems :o
+ Skins.Message(mtInfo, buf);
+
+ free(buf);
+
+ return true;
+ }
+
+ return false;
+}
+
+//***************************************************************************
+// Recording
+//***************************************************************************
+
+void cPinStatusMonitor::RecordingFile(const char* FileName)
+{
+ char* path = 0;
+ cRecordControl* rc;
+ FILE* f;
+
+ if (!FileName || !strlen(FileName))
+ return;
+
+ rc = cRecordControls::GetRecordControl(FileName);
+
+ tell(eloDebug, "checking if autoprotection for '%s' is needed", FileName);
+
+ if (rc && rc->Timer() && rc->Timer()->Channel())
+ {
+ if (rc->Timer()->FskProtection())
+ {
+ int res;
+ res = asprintf(&path, "%s/%s", FileName, PROTECTION_FILE);
+ if (res < 0) ; // memory problems :o
+
+ tell(eloDebug, "autoprotecting recording due to '%s'; channel '%s'; file '%s'",
+ rc->Timer()->FskProtection() ? "timer configuration" : "of protected channel",
+ rc->Timer()->Channel()->Name(), path);
+
+ f = fopen(path, "w");
+ if (f) fclose(f);
+
+ free(path);
+ }
+ }
+}
+
+//***************************************************************************
+// Get Event Of
+//***************************************************************************
+
+const cEvent* cPinStatusMonitor::GetEventOf(const cSchedules* schedules, const cChannel* Channel)
+{
+ const cSchedule* schedule;
+ const cEvent* event;
+
+ if (!(schedule = schedules->GetSchedule(Channel->GetChannelID())))
+ return 0;
+
+ if (!(event = schedule->GetPresentEvent()))
+ return 0;
+
+ return event;
+}
+
+//***************************************************************************
+// Timer Creation
+//***************************************************************************
+
+void cPinStatusMonitor::TimerCreation(cTimer* Timer, const cEvent* Event)
+{
+ int fsk = 0;
+
+ if (!Timer || !Event || !Timer->Channel())
+ return;
+
+ tell(eloDebug, "Timer creation, event '%s', protection mode (%d)",
+ Event->Title(), cPinPlugin::autoProtectionMode);
+
+ switch (cPinPlugin::autoProtectionMode)
+ {
+ case cPinPlugin::apmAlways: fsk = 1; break;
+ case cPinPlugin::apmNever: fsk = 0; break;
+
+ case cPinPlugin::apmIntelligent:
+ {
+ tell(eloDebug, "Checking protection for channel '%s' at (%ld))",
+ Timer->Channel()->Name(), Event->StartTime());
+
+ fsk = (cPinPlugin::getObject())->channelProtected(
+ Timer->Channel()->Name(), Event->StartTime())
+ || (cPinPlugin::getObject())->broadcastProtected(Event->Title());
+
+ break;
+ }
+ }
+
+ Timer->SetFskProtection(fsk);
+}
+
+//***************************************************************************
+// Plugin Protected
+//***************************************************************************
+
+bool cPinStatusMonitor::PluginProtected(cPlugin* Plugin, int menuView)
+{
+ char* buf;
+
+ if (cOsd::pinValid)
+ return false;
+
+ if (menuView && !cPinPlugin::hideProtectedPlugins)
+ return false;
+
+ if (!Plugin)
+ return false;
+
+ // check if plugin is protected
+
+ tell(eloDebug, "checking protection of plugin '%s'",Plugin->MainMenuEntry());
+
+ if ((cPinPlugin::getObject())->pluginProtected(Plugin->Name()))
+ {
+ tell(eloDebug, "plugin '%s' is protected", Plugin->MainMenuEntry());
+
+ if (!menuView)
+ {
+ int res;
+ res = asprintf(&buf, "%s %s", Plugin->MainMenuEntry(), tr("is protected"));
+ if (res < 0) ; // memory problems :o
+ Skins.Message(mtInfo, buf);
+ free(buf);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+//***************************************************************************
+// Menu Item Protectes
+//***************************************************************************
+
+bool cPinStatusMonitor::MenuItemProtected(const char* Name, int menuView)
+{
+ char* buf;
+ const char* name;
+
+ if (!Name)
+ return false;
+
+ if (!(name = translations.lookup(Name)))
+ {
+ name = tr(Str::stripHotKey(Name));
+ translations.append(Name, name);
+ }
+
+ tell(eloDebug, "translation: '%s' -> '%'s ",
+ Str::stripHotKey(Name), name);
+
+ if (menuView)
+ (cPinPlugin::getObject())->menuItemAppend(name);
+
+ if (cOsd::pinValid)
+ return false;
+
+ if (menuView && !cPinPlugin::hideProtectedMenus)
+ return false;
+
+ // check if menu item is protected
+
+ tell(eloDebug, "checking protection of menu entry '%s' for '%s'",
+ name, menuView ? "view": "execution");
+
+ if ((cPinPlugin::getObject())->menuItemProtected(name))
+ {
+ tell(eloDebug, "menu entry '%s' is protected", name);
+
+ if (!menuView)
+ {
+ int res;
+ res = asprintf(&buf, "%s %s", name, tr("is protected"));
+ if (res < 0) ; // memory problems :o
+ Skins.Message(mtInfo, buf);
+ free(buf);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+//***************************************************************************
+
+VDRPLUGINCREATOR(cPinPlugin);