📄 sc.c
字号:
if(dev->Cam()) str=dev->Cam()->CurrentKeyStr(num); if(!str && num==0 && ScSetup.CapCheck(CardNum)) str=strdup(tr("(none)")); } return str;}bool cSoftCAM::Active(bool log){ for(int n=cDevice::NumDevices(); --n>=0;) { cScDvbDevice *dev=dynamic_cast<cScDvbDevice *>(cDevice::GetDevice(n)); if(dev && dev->Cam() && dev->Cam()->Active(log)) return true; } return false;}void cSoftCAM::SetLogStatus(int CardNum, const cEcmInfo *ecm, bool on){ cScDvbDevice *dev=dynamic_cast<cScDvbDevice *>(cDevice::GetDevice(CardNum)); if(dev && dev->Cam()) dev->Cam()->LogEcmStatus(ecm,on);}void cSoftCAM::AddHook(int CardNum, cLogHook *hook){ cScDvbDevice *dev=dynamic_cast<cScDvbDevice *>(cDevice::GetDevice(CardNum)); if(dev && dev->Cam()) dev->Cam()->AddHook(hook);}bool cSoftCAM::TriggerHook(int CardNum, int id){ cScDvbDevice *dev=dynamic_cast<cScDvbDevice *>(cDevice::GetDevice(CardNum)); return dev && dev->Cam() && dev->Cam()->TriggerHook(id);}// --- cScHousekeeper ----------------------------------------------------------class cScHousekeeper : public cThread {protected: virtual void Action(void);public: cScHousekeeper(void); ~cScHousekeeper(); };cScHousekeeper::cScHousekeeper(void):cThread("SC housekeeper"){ Start();}cScHousekeeper::~cScHousekeeper(){ Cancel(3);}void cScHousekeeper::Action(void){ int c=0; while(Running()) { if(++c==20) { c=0; for(int n=cDevice::NumDevices(); --n>=0;) { cScDvbDevice *dev=dynamic_cast<cScDvbDevice *>(cDevice::GetDevice(n)); if(dev && dev->Cam()) dev->Cam()->HouseKeeping(); } } if(Feature.KeyFile()) keys.HouseKeeping(); if(!cSoftCAM::Active(false)) cStructLoaders::Purge(); cStructLoaders::Load(true); cStructLoaders::Save(); cCondWait::SleepMs(987); }}#ifndef STATICBUILD// --- cScDll ------------------------------------------------------------------class cScDll : public cSimpleItem {private: char *fileName; void *handle;public: cScDll(const char *FileName); ~cScDll(); bool Load(void); };cScDll::cScDll(const char *FileName){ fileName=strdup(FileName); handle=0;}cScDll::~cScDll(){ if(handle) dlclose(handle); free(fileName);}bool cScDll::Load(void){ char *base=rindex(fileName,'/'); if(!base) base=fileName; PRINTF(L_CORE_DYN,"loading library: %s",base); if(!handle) { handle=dlopen(fileName,RTLD_NOW|RTLD_LOCAL); if(handle) return true; PRINTF(L_GEN_ERROR,"dload: %s: %s",base,dlerror()); } return false;}// --- cScDlls -----------------------------------------------------------------#define LIBSC_PREFIX "libsc-"#define SO_INDICATOR ".so."class cScDlls : public cSimpleList<cScDll> {private: void *handle;public: cScDlls(void); ~cScDlls(); bool Load(void); };cScDlls::cScDlls(void){ handle=0;}cScDlls::~cScDlls(){ Clear(); if(handle) dlclose(handle); PRINTF(L_CORE_DYN,"unload done");}bool cScDlls::Load(void){ Dl_info info; static int marker=0; if(!dladdr((void *)&marker,&info)) { PRINTF(L_GEN_ERROR,"dladdr: %s",dlerror()); return false; } // we have to re-dlopen our selfs as VDR doesn't use RTLD_GLOBAL // but our symbols have to be available to the sub libs. handle=dlopen(info.dli_fname,RTLD_NOW|RTLD_GLOBAL); if(!handle) { PRINTF(L_GEN_ERROR,"dlopen myself: %s",dlerror()); return false; } char *path=strdup(info.dli_fname); char *p; if((p=rindex(path,'/'))) *p=0; PRINTF(L_CORE_DYN,"library path %sn",path); char pat[32]; snprintf(pat,sizeof(pat),"%s*-%d%s%s",LIBSC_PREFIX,SCAPIVERS,SO_INDICATOR,APIVERSION); bool res=true; cReadDir dir(path); struct dirent *e; while((e=dir.Next())) { if(!fnmatch(pat,e->d_name,FNM_PATHNAME|FNM_NOESCAPE)) { cScDll *dll=new cScDll(AddDirectory(path,e->d_name)); if(dll) { if(!dll->Load()) res=false; Ins(dll); } } } free(path); return res;}#endif// --- cScPlugin ---------------------------------------------------------------class cScPlugin : public cPlugin {private:#ifndef STATICBUILD cScDlls dlls;#endif cScHousekeeper *keeper;public: cScPlugin(void); virtual ~cScPlugin(); virtual const char *Version(void); virtual const char *Description(void); virtual const char *CommandLineHelp(void); virtual bool ProcessArgs(int argc, char *argv[]); virtual bool Initialize(void); virtual bool Start(void); virtual void Stop(void);#ifndef SASC virtual void MainThreadHook(void);#endif virtual cMenuSetupPage *SetupMenu(void); virtual bool SetupParse(const char *Name, const char *Value); virtual const char **SVDRPHelpPages(void); virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); };cScPlugin::cScPlugin(void){ static const char *logg[] = { trNOOP("off"),trNOOP("active CAIDs"),trNOOP("all CAIDs") }; static const char *skey[] = { trNOOP("comment out"),trNOOP("remove") }; static const char *ecache[] = { trNOOP("enabled"),trNOOP("read-only"),trNOOP("off") }; ScOpts=new cOpts(0,9); ScOpts->Add(new cOptSel ("AutoUpdate" ,trNOOP("Update keys (AU)") ,&ScSetup.AutoUpdate,3,logg)); ScOpts->Add(new cOptBool ("PrestartAU" ,trNOOP("Start AU on EPG scan") ,&ScSetup.PrestartAU)); ScOpts->Add(new cOptSel ("SuperKeys" ,trNOOP("Superseded keys") ,&ScSetup.SuperKeys,2,skey)); ScOpts->Add(new cOptBool ("ConcurrentFF" ,trNOOP("Concurrent FF streams"),&ScSetup.ConcurrentFF)); ScOpts->Add(new cOptBool ("ForceTranfer" ,trNOOP("Force TransferMode") ,&ScSetup.ForceTransfer)); ScOpts->Add(new cOptBool ("LocalPriority",trNOOP("Prefer local systems") ,&ScSetup.LocalPriority)); ScOpts->Add(new cOptSel ("EcmCache" ,trNOOP("ECM cache") ,&ScSetup.EcmCache,3,ecache)); ScOpts->Add(new cOptMInt ("ScCaps" ,trNOOP("Active on DVB card") , ScSetup.ScCaps,MAXSCCAPS,0)); ScOpts->Add(new cOptMInt ("CaIgnore" ,trNOOP("Ignore CAID") , ScSetup.CaIgnore,MAXCAIGN,2)); LogOpts=new cOpts(0,6); LogOpts->Add(new cOptBool ("LogConsole" ,trNOOP("Log to console") ,&logcfg.logCon)); LogOpts->Add(new cOptBool ("LogFile" ,trNOOP("Log to file") ,&logcfg.logFile)); LogOpts->Add(new cOptStr ("LogFileName" ,trNOOP("Filename") ,logcfg.logFilename,sizeof(logcfg.logFilename),FileNameChars)); LogOpts->Add(new cOptInt ("LogFileLimit",trNOOP("Filesize limit (KB)") ,&logcfg.maxFilesize,0,2000000)); LogOpts->Add(new cOptBool ("LogSyslog" ,trNOOP("Log to syslog") ,&logcfg.logSys)); LogOpts->Add(new cOptBool ("LogUserMsg" ,trNOOP("Show user messages") ,&logcfg.logUser));#ifndef STATICBUILD dlls.Load();#endif cScDvbDevice::Capture(); keeper=0;}cScPlugin::~cScPlugin(){ delete keeper; delete ScOpts; delete LogOpts;}bool cScPlugin::Initialize(void){ PRINTF(L_GEN_INFO,"SC version %s initializing",ScVersion); return cScDvbDevice::Initialize();}bool cScPlugin::Start(void){ PRINTF(L_GEN_INFO,"SC version %s starting",ScVersion); if(APIVERSNUM<MINAPIVERSNUM) { PRINTF(L_GEN_ERROR,"SC plugin needs at least VDR API version %d.%d.%d",MIN_VERS,MIN_MAJOR,MIN_MINOR); return false; } if(sizeof(int)!=4) { PRINTF(L_GEN_ERROR,"compiled with 'int' as %d bit. Only supporting 32 bit.",(int)sizeof(int)*8); return false; } if(sizeof(long long)!=8) { PRINTF(L_GEN_ERROR,"compiled with 'long long' as %d bit. Only supporting 64 bit.",(int)sizeof(long long)*8); return false; } ScPlugin=this;#if APIVERSNUM < 10507 RegisterI18n(ScPhrases);#endif const char *cfgdir=ConfigDirectory(cfgsub); filemaps.SetCfgDir(cfgdir); cStructLoaders::SetCfgDir(cfgdir); ScSetup.Check(); if(!cSoftCAM::Load(cfgdir)) return false; if(Feature.SmartCard()) {#ifdef DEFAULT_PORT smartcards.AddPort(DEFAULT_PORT);#endif smartcards.LaunchWatcher(); } cScDvbDevice::Startup(); keeper=new cScHousekeeper; return true;}void cScPlugin::Stop(void){ delete keeper; keeper=0; cScDvbDevice::Shutdown(); LogStatsDown(); cSoftCAM::Shutdown();#if APIVERSNUM < 10507 RegisterI18n(NULL);#endif PRINTF(L_GEN_DEBUG,"SC cleanup done");}const char *cScPlugin::Version(void){ return ScVersion;}const char *cScPlugin::Description(void){ return tr("A software emulated CAM");}const char *cScPlugin::CommandLineHelp(void){ static char *help_str=0; free(help_str); // for easier orientation, this is column 80| asprintf(&help_str," -B N --budget=N forces DVB device N to budget mode (using FFdecsa)\n" " -I --inverse-cd use inverse CD detection for the next serial device\n" " -R --inverse-rst use inverse RESET for the next serial device\n" " -C FREQ --clock=FREQ use FREQ as clock for the card reader on the next\n" " serial device (rather than 3.5712 MHz\n" " -s DEV --serial=DEV activate Phoenix ISO interface on serial device DEV\n" " (default: %s)\n" " -d CMD --dialup=CMD call CMD to start/stop dialup-network\n" " (default: %s)\n" " -t SECS --timeout=SECS shutdown timeout for dialup-network\n" " (default: %d secs)\n", "none","none",netTimeout/1000 ); return help_str;}bool cScPlugin::ProcessArgs(int argc, char *argv[]){ static struct option long_options[] = { { "serial", required_argument, NULL, 's' }, { "inverse-cd", no_argument, NULL, 'I' }, { "inverse-rst", no_argument, NULL, 'R' }, { "clock", required_argument, NULL, 'C' }, { "dialup", required_argument, NULL, 'd' }, { "external-au", required_argument, NULL, 'E' }, { "budget", required_argument, NULL, 'B' }, { NULL } }; int c, option_index=0; bool invCD=false, invRST=false; int clock=0; while((c=getopt_long(argc,argv,"d:s:t:B:C:E:IR",long_options,&option_index))!=-1) { switch (c) { case 'I': invCD=true; break; case 'R': invRST=true; break; case 'C': clock=atoi(optarg); break; case 's': smartcards.AddPort(optarg,invCD,invRST,clock); invCD=false; invRST=false; clock=0; break; case 'd': netscript=optarg; break; case 't': netTimeout=atoi(optarg)*1000; break; case 'E': externalAU=optarg; break; case 'B': cScDvbDevice::SetForceBudget(atoi(optarg)); break; default: return false; } } return true;}cMenuSetupPage *cScPlugin::SetupMenu(void){ return new cMenuSetupSc(ConfigDirectory(cfgsub));}bool cScPlugin::SetupParse(const char *Name, const char *Value){ if((ScOpts && ScOpts->Parse(Name,Value)) || (LogOpts && LogOpts->Parse(Name,Value)) || cSystems::ConfigParse(Name,Value)) ; else if(!strcasecmp(Name,"LogConfig")) cLogging::ParseConfig(Value); else return false; return true;}#ifndef SASCvoid cScPlugin::MainThreadHook(void){ int n=0; cUserMsg *um; while(++n<=10 && (um=ums.GetQueuedMsg())) { Skins.QueueMessage(mtInfo,um->Message()); delete um; }}#endif //SASCconst char **cScPlugin::SVDRPHelpPages(void){ static const char *HelpPages[] = { "RELOAD\n" " Reload all configuration files.", "KEY <string>\n", " Add key to the key database (as if it was received from EMM stream).", "LOG <on|off> <class>[,<class>...]\n" " Turn the given message class(es) on or off.", "LOGCFG\n" " Display available message classes and their status.", "LOGFILE <on|off> [<filename>]\n" " Enables/disables logging to file and optionaly sets the filename.", NULL }; return HelpPages;}cString cScPlugin::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode){ if(!strcasecmp(Command,"RELOAD")) { if(cSoftCAM::Active(true)) { ReplyCode=550; return "Softcam active. Can't reload files now"; } else { if(cSoftCAM::Load(ConfigDirectory(cfgsub))) return "Files reloaded successfully"; else { ReplyCode=901; return "Reloading files not entirely successfull"; } } } else if(!strcasecmp(Command,"KEY")) { if(Option && *Option) { if(keys.NewKeyParse(skipspace(Option),"from SVDR")) return "Key update successfull"; else { ReplyCode=901; return "Key already known or invalid key format"; } } else { ReplyCode=501; return "Missing args"; } } else if(!strcasecmp(Command,"LOG")) { if(Option && *Option) { char tmp[1024]; strn0cpy(tmp,Option,sizeof(tmp)); char *opt=tmp; opt=skipspace(opt); bool mode; if(!strncasecmp(opt,"ON ",3)) { mode=true; opt+=3; } else if(!strncasecmp(opt,"OFF ",4)) { mode=false; opt+=4; } else { ReplyCode=501; return "Bad mode, valid: on off"; } do { char *s=index(opt,','); if(s) *s++=0; int c=cLogging::GetClassByName(opt); if(c>=0) cLogging::SetModuleOption(c,mode); else { ReplyCode=501; return "Unknown message class"; } opt=s; } while(opt); ScSetup.Store(true); Setup.Save(); return "Done"; } else { ReplyCode=501; return "Missing args"; } } else if(!strcasecmp(Command,"LOGCFG")) { cLineBuff lb(256); for(int m=1; m<LMOD_MAX; m++) { const char *name=cLogging::GetModuleName(LCLASS(m,0)); if(name) { int o=cLogging::GetModuleOptions(LCLASS(m,0)); if(o>=0) { for(int i=0; i<LOPT_NUM; i++) { const char *opt; if(i==0) opt="enable"; else opt=cLogging::GetOptionName(LCLASS(m,1<<i)); if(opt) lb.Printf("%s.%s %s\n",name,opt,(o&(1<<i))?"on":"off"); } } } } if(lb.Length()>0) return lb.Line(); ReplyCode=901; return "No config available"; } else if(!strcasecmp(Command,"LOGFILE")){ if(Option && *Option) { char tmp[1024]; strn0cpy(tmp,Option,sizeof(tmp)); char *opt=tmp; opt=skipspace(opt); bool mode; if(!strncasecmp(opt,"ON",2)) { mode=true; opt+=2; } else if(!strncasecmp(opt,"OFF",3)) { mode=false; opt+=3; } else { ReplyCode=501; return "Bad mode, valid: on off"; } cLineBuff lb(256); if(mode) { logcfg.logFile=true; if(*opt==' ' || *opt=='\t') { opt=stripspace(skipspace(opt)); strn0cpy(logcfg.logFilename,opt,sizeof(logcfg.logFilename)); } lb.Printf("logging to file enabled, file %s",logcfg.logFilename); } else { logcfg.logFile=false; lb.Printf("logging to file disabled"); } ScSetup.Store(true); Setup.Save(); return lb.Line(); } else { ReplyCode=501; return "Missing args"; } } return NULL;}VDRPLUGINCREATOR(cScPlugin); // Don't touch this!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -