|
SASC
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 #include <malloc.h> 00021 #include <stdlib.h> 00022 #include <limits.h> 00023 #include <getopt.h> 00024 #include <typeinfo> 00025 #ifndef STATICBUILD 00026 #include <dlfcn.h> 00027 #include <dirent.h> 00028 #include <fnmatch.h> 00029 #endif 00030 00031 #include <vdr/plugin.h> 00032 #include <vdr/menuitems.h> 00033 #include <vdr/status.h> 00034 #include <vdr/dvbdevice.h> 00035 #include <vdr/channels.h> 00036 #include <vdr/interface.h> 00037 #include <vdr/menu.h> 00038 #include <vdr/tools.h> 00039 #include <vdr/config.h> 00040 00041 #include "scsetup.h" 00042 #include "filter.h" 00043 #include "system.h" 00044 #include "cam.h" 00045 #include "global.h" 00046 #include "device.h" 00047 #include "smartcard.h" 00048 #include "data.h" 00049 #include "network.h" 00050 #include "misc.h" 00051 #include "opts.h" 00052 #include "i18n.h" 00053 #include "log-core.h" 00054 #include "version.h" 00055 00056 #define MIN_VERS 1 // required VDR version 00057 #define MIN_MAJOR 6 00058 #define MIN_MINOR 0 00059 #define MINAPIVERSNUM 10600 00060 00061 // some sanity checks 00062 #ifdef HAVE_SOFTCSA 00063 #error softcsa/ffdecsa patch MUST NOT be applied. Next time read the README first. 00064 #endif 00065 #ifdef VDR_IS_SC_PATCHED 00066 #error You MUST NOT patch the VDR core. Next time read the README first. 00067 #endif 00068 #if APIVERSNUM<MINAPIVERSNUM 00069 #error Your VDR API version is too old. See README. 00070 #endif 00071 00072 static cPlugin *ScPlugin; 00073 static cOpts *ScOpts, *LogOpts; 00074 static const char * const cfgsub="sc"; 00075 00076 static const struct LogModule lm_core = { 00077 (LMOD_ENABLE|L_CORE_ALL)&LOPT_MASK, 00078 (LMOD_ENABLE|L_CORE_LOAD|L_CORE_ECM|L_CORE_PIDS|L_CORE_AU|L_CORE_AUSTATS|L_CORE_NET|L_CORE_CI|L_CORE_SC|L_CORE_HOOK|L_CORE_OVER)&LOPT_MASK, 00079 "core", 00080 { "load","action","ecm","ecmProc","pids","au","auStats","auExtra","auExtern", 00081 "caids","keys","dynamic","csa","ci","av7110","net","netData","msgcache", 00082 "serial","smartcard","hook","ciFull","csaVerb","override" } 00083 }; 00084 ADD_MODULE(L_CORE,lm_core) 00085 00086 // --- cMenuEditCapItem -------------------------------------------------------- 00087 00088 class cMenuEditCapItem : public cMenuEditIntItem { 00089 protected: 00090 virtual void Set(void); 00091 public: 00092 cMenuEditCapItem(const char *Name, int *Value); 00093 eOSState ProcessKey(eKeys Key); 00094 }; 00095 00096 cMenuEditCapItem::cMenuEditCapItem(const char *Name, int *Value) 00097 :cMenuEditIntItem(Name, Value, 0) 00098 { 00099 Set(); 00100 } 00101 00102 void cMenuEditCapItem::Set(void) 00103 { 00104 if(!*value) SetValue(tr("off")); 00105 else cMenuEditIntItem::Set(); 00106 } 00107 00108 eOSState cMenuEditCapItem::ProcessKey(eKeys Key) 00109 { 00110 eOSState state = cMenuEditItem::ProcessKey(Key); 00111 if(state==osUnknown) 00112 state=cMenuEditIntItem::ProcessKey(Key); 00113 return state; 00114 } 00115 00116 // --- cMenuEditHexItem ------------------------------------------------------ 00117 00118 class cMenuEditHexItem : public cMenuEditItem { 00119 private: 00120 bool abc, isOn; 00121 // 00122 void SetButtons(bool on); 00123 protected: 00124 int *value; 00125 int min, max; 00126 // 00127 virtual void Set(void); 00128 public: 00129 cMenuEditHexItem(const char *Name, int *Value, int Min=0, int Max=INT_MAX); 00130 virtual eOSState ProcessKey(eKeys Key); 00131 }; 00132 00133 cMenuEditHexItem::cMenuEditHexItem(const char *Name, int *Value, int Min, int Max) 00134 :cMenuEditItem(Name) 00135 { 00136 value=Value; min=Min; max=Max; 00137 if(*value<min) *value=min; 00138 else if(*value>max) *value=max; 00139 Set(); 00140 abc=true; isOn=false; 00141 } 00142 00143 void cMenuEditHexItem::SetButtons(bool on) 00144 { 00145 if(on) { 00146 if(abc) cSkinDisplay::Current()->SetButtons("A","B","C","D-F"); 00147 else cSkinDisplay::Current()->SetButtons("D","E","F","A-C"); 00148 isOn=true; 00149 } 00150 else { 00151 cSkinDisplay::Current()->SetButtons(0); 00152 isOn=false; 00153 } 00154 } 00155 00156 void cMenuEditHexItem::Set(void) 00157 { 00158 char buf[16]; 00159 snprintf(buf,sizeof(buf),"%X",*value); 00160 SetValue(buf); 00161 } 00162 00163 eOSState cMenuEditHexItem::ProcessKey(eKeys Key) 00164 { 00165 switch(NORMALKEY(Key)) { 00166 case kUp: 00167 case kDown: 00168 if(isOn) SetButtons(false); 00169 break; 00170 default: 00171 if(!isOn) SetButtons(true); 00172 break; 00173 } 00174 eOSState state=cMenuEditItem::ProcessKey(Key); 00175 if(state!=osUnknown) return state; 00176 00177 int newValue=*value; 00178 bool IsRepeat=Key & k_Repeat; 00179 Key=NORMALKEY(Key); 00180 switch(Key) { 00181 case kBlue: 00182 abc=!abc; SetButtons(true); 00183 break; 00184 case kRed: 00185 case kGreen: 00186 case kYellow: 00187 case k0 ... k9: 00188 { 00189 if(fresh) { newValue=0; fresh=false; } 00190 int add; 00191 if(Key>=kRed && Key<=kYellow) add=(abc ? 10:13)+(Key-kRed); 00192 else add=(Key-k0); 00193 newValue=newValue*16+add; 00194 break; 00195 } 00196 case kLeft: 00197 newValue=*value-1; fresh=true; 00198 if(!IsRepeat && newValue<min) newValue=max; 00199 break; 00200 case kRight: 00201 newValue=*value+1; fresh=true; 00202 if(!IsRepeat && newValue>max) newValue=min; 00203 break; 00204 default: 00205 if(*value<min) { *value=min; Set(); } 00206 if(*value>max) { *value=max; Set(); } 00207 return osUnknown; 00208 } 00209 if(newValue!=*value && (!fresh || min<=newValue) && newValue<=max) { 00210 *value=newValue; 00211 Set(); 00212 } 00213 return osContinue; 00214 } 00215 00216 // --- cScInfoItem ------------------------------------------------------------- 00217 00218 class cScInfoItem : public cOsdItem { 00219 private: 00220 void SetValue(const char *Name, const char *Value); 00221 // 00222 int ident; 00223 public: 00224 cScInfoItem(const char *Name, int Value, eOSState State=osUnknown); 00225 cScInfoItem(const char *Name, const char *Value=0, eOSState State=osUnknown); 00226 void Ident(int id) { ident=id; } 00227 int Ident(void) { return ident; } 00228 }; 00229 00230 cScInfoItem::cScInfoItem(const char *Name, int Value, eOSState State) 00231 :cOsdItem(State) 00232 { 00233 char buf[16]; 00234 snprintf(buf,sizeof(buf),"%d",Value); 00235 SetValue(Name,buf); 00236 if(State==osUnknown) SetSelectable(false); 00237 } 00238 00239 cScInfoItem::cScInfoItem(const char *Name, const char *Value, eOSState State) 00240 :cOsdItem(State) 00241 { 00242 SetValue(Name,Value); 00243 if(State==osUnknown) SetSelectable(false); 00244 } 00245 00246 void cScInfoItem::SetValue(const char *Name, const char *Value) 00247 { 00248 char *buff=bprintf(Value ? "%s:\t%s":"%s",Name,Value); 00249 SetText(buff,false); 00250 cStatus::MsgOsdCurrentItem(buff); 00251 ident=-1; 00252 } 00253 00254 // --- cOpt -------------------------------------------------------------------- 00255 00256 cOpt::cOpt(const char *Name, const char *Title) 00257 { 00258 name=Name; title=Title; 00259 fullname=0; persistant=true; 00260 } 00261 00262 cOpt::~cOpt() 00263 { 00264 free(fullname); 00265 } 00266 00267 const char *cOpt::FullName(const char *PreStr) 00268 { 00269 if(PreStr) { 00270 free(fullname); 00271 fullname=bprintf("%s.%s",PreStr,name); 00272 return fullname; 00273 } 00274 else return name; 00275 } 00276 00277 // --- cOptInt ----------------------------------------------------------------- 00278 00279 cOptInt::cOptInt(const char *Name, const char *Title, int *Storage, int Min, int Max) 00280 :cOpt(Name,Title) 00281 { 00282 storage=Storage; min=Min; max=Max; 00283 } 00284 00285 void cOptInt::Parse(const char *Value) 00286 { 00287 *storage=atoi(Value); 00288 } 00289 00290 void cOptInt::Backup(void) 00291 { 00292 value=*storage; 00293 } 00294 00295 bool cOptInt::Set(void) 00296 { 00297 if(value!=*storage) { *storage=value; return true; } 00298 return false; 00299 } 00300 00301 void cOptInt::Store(const char *PreStr) 00302 { 00303 ScPlugin->SetupStore(FullName(PreStr),*storage); 00304 } 00305 00306 void cOptInt::Create(cOsdMenu *menu) 00307 { 00308 menu->Add(new cMenuEditIntItem(tr(title),&value,min,max)); 00309 } 00310 00311 // --- cOptSel ----------------------------------------------------------------- 00312 00313 cOptSel::cOptSel(const char *Name, const char *Title, int *Storage, int NumStr, const char * const *Strings) 00314 :cOptInt(Name,Title,Storage,0,NumStr) 00315 { 00316 strings=Strings; 00317 trStrings=0; 00318 } 00319 00320 cOptSel::~cOptSel() 00321 { 00322 free(trStrings); 00323 } 00324 00325 void cOptSel::Create(cOsdMenu *menu) 00326 { 00327 free(trStrings); 00328 if((trStrings=MALLOC(const char *,max))) { 00329 for(int i=0; i<max ; i++) trStrings[i]=tr(strings[i]); 00330 menu->Add(new cMenuEditStraItem(tr(title),&value,max,trStrings)); 00331 } 00332 } 00333 00334 // --- cOptBool ----------------------------------------------------------------- 00335 00336 cOptBool::cOptBool(const char *Name, const char *Title, int *Storage) 00337 :cOptInt(Name,Title,Storage,0,1) 00338 {} 00339 00340 void cOptBool::Create(cOsdMenu *menu) 00341 { 00342 menu->Add(new cMenuEditBoolItem(tr(title),&value)); 00343 } 00344 00345 // --- cOptStr ----------------------------------------------------------------- 00346 00347 cOptStr::cOptStr(const char *Name, const char *Title, char *Storage, int Size, const char *Allowed) 00348 :cOpt(Name,Title) 00349 { 00350 storage=Storage; size=Size; allowed=Allowed; 00351 value=MALLOC(char,size); 00352 } 00353 00354 cOptStr::~cOptStr() 00355 { 00356 free(value); 00357 } 00358 00359 void cOptStr::Parse(const char *Value) 00360 { 00361 strn0cpy(storage,Value,size); 00362 } 00363 00364 void cOptStr::Backup(void) 00365 { 00366 strn0cpy(value,storage,size); 00367 } 00368 00369 bool cOptStr::Set(void) 00370 { 00371 if(strcmp(value,storage)) { strn0cpy(storage,value,size); return true; } 00372 return false; 00373 } 00374 00375 void cOptStr::Store(const char *PreStr) 00376 { 00377 ScPlugin->SetupStore(FullName(PreStr),storage); 00378 } 00379 00380 void cOptStr::Create(cOsdMenu *menu) 00381 { 00382 menu->Add(new cMenuEditStrItem(tr(title),value,size,allowed)); 00383 } 00384 00385 // --- cOptMInt ---------------------------------------------------------------- 00386 00387 class cOptMInt : public cOpt { 00388 protected: 00389 int *storage, *value; 00390 int size, mode, len; 00391 public: 00392 cOptMInt(const char *Name, const char *Title, int *Storage, int Size, int Mode); 00393 virtual ~cOptMInt(); 00394 virtual void Parse(const char *Value); 00395 virtual void Backup(void); 00396 virtual bool Set(void); 00397 virtual void Store(const char *PreStr); 00398 virtual void Create(cOsdMenu *menu); 00399 }; 00400 00401 // mode: 0-Cap 1-Int 2-Hex 00402 00403 cOptMInt::cOptMInt(const char *Name, const char *Title, int *Storage, int Size, int Mode) 00404 :cOpt(Name,Title) 00405 { 00406 storage=Storage; size=Size; mode=Mode; len=sizeof(int)*size; 00407 value=MALLOC(int,size); 00408 } 00409 00410 cOptMInt::~cOptMInt() 00411 { 00412 free(value); 00413 } 00414 00415 void cOptMInt::Parse(const char *Value) 00416 { 00417 memset(storage,0,len); 00418 int i=0; 00419 while(1) { 00420 char *p; 00421 const int c=strtol(Value,&p,mode>1 ? 16:10); 00422 if(p==Value || i>=size) return; 00423 if(c>0) storage[i++]=c; 00424 Value=p; 00425 } 00426 } 00427 00428 void cOptMInt::Backup(void) 00429 { 00430 memcpy(value,storage,len); 00431 } 00432 00433 bool cOptMInt::Set(void) 00434 { 00435 if(memcmp(value,storage,len)) { 00436 memset(storage,0,len); 00437 for(int i=0, k=0; i<size; i++) if(value[i]>0) storage[k++]=value[i]; 00438 return true; 00439 } 00440 return false; 00441 } 00442 00443 void cOptMInt::Store(const char *PreStr) 00444 { 00445 char b[256]; 00446 int p=0; 00447 for(int i=0; i<size; i++) 00448 if(storage[i] || mode==0) p+=snprintf(b+p,sizeof(b)-p,mode>1 ? "%x ":"%d ",storage[i]); 00449 ScPlugin->SetupStore(FullName(PreStr),p>0?b:0); 00450 } 00451 00452 void cOptMInt::Create(cOsdMenu *menu) 00453 { 00454 for(int i=0; i<size; i++) { 00455 const char *buff=tr(title); 00456 switch(mode) { 00457 case 0: menu->Add(new cMenuEditCapItem(buff,&value[i])); break; 00458 case 1: menu->Add(new cMenuEditIntItem(buff,&value[i],0,65535)); break; 00459 case 2: menu->Add(new cMenuEditHexItem(buff,&value[i],0,65535)); break; 00460 } 00461 if(value[i]==0) break; 00462 } 00463 } 00464 00465 // --- cOpts ------------------------------------------------------------------- 00466 00467 cOpts::cOpts(const char *PreStr, int NumOpts) 00468 { 00469 preStr=PreStr; 00470 numOpts=NumOpts; numAdd=0; 00471 if((opts=MALLOC(cOpt *,numOpts))) memset(opts,0,sizeof(cOpt *)*numOpts); 00472 } 00473 00474 cOpts::~cOpts() 00475 { 00476 if(opts) { 00477 for(int i=0; i<numOpts; i++) delete opts[i]; 00478 free(opts); 00479 } 00480 } 00481 00482 void cOpts::Add(cOpt *opt) 00483 { 00484 if(opts && numAdd<numOpts) opts[numAdd++]=opt; 00485 } 00486 00487 bool cOpts::Parse(const char *Name, const char *Value) 00488 { 00489 if(opts) { 00490 for(int i=0; i<numAdd; i++) 00491 if(opts[i] && opts[i]->Persistant() && !strcasecmp(Name,opts[i]->Name())) { 00492 opts[i]->Parse(Value); 00493 return true; 00494 } 00495 } 00496 return false; 00497 } 00498 00499 bool cOpts::Store(bool AsIs) 00500 { 00501 bool res=false; 00502 if(opts) { 00503 for(int i=0; i<numAdd; i++) 00504 if(opts[i]) { 00505 if(!AsIs && opts[i]->Set()) res=true; 00506 if(opts[i]->Persistant()) opts[i]->Store(preStr); 00507 } 00508 } 00509 return res; 00510 } 00511 00512 void cOpts::Backup(void) 00513 { 00514 if(opts) { 00515 for(int i=0; i<numAdd; i++) 00516 if(opts[i]) opts[i]->Backup(); 00517 } 00518 } 00519 00520 void cOpts::Create(cOsdMenu *menu) 00521 { 00522 if(opts) { 00523 for(int i=0; i<numAdd; i++) 00524 if(opts[i]) opts[i]->Create(menu); 00525 } 00526 } 00527 00528 // --- cSoftCAM --------------------------------------------------------------- 00529 00530 class cSoftCAM { 00531 public: 00532 static bool Load(const char *cfgdir); 00533 static void Shutdown(void); 00534 }; 00535 00536 bool cSoftCAM::Load(const char *cfgdir) 00537 { 00538 if(!Feature.KeyFile()) keys.Disable(); 00539 if(!Feature.SmartCard()) smartcards.Disable(); 00540 cStructLoaders::Load(false); 00541 if(Feature.KeyFile() && keys.Count()<1) 00542 PRINTF(L_GEN_ERROR,"no keys loaded for softcam!"); 00543 if(!cSystems::Init(cfgdir)) return false; 00544 srand(time(0)); 00545 return true; 00546 } 00547 00548 void cSoftCAM::Shutdown(void) 00549 { 00550 cStructLoaders::Save(true); 00551 cSystems::Clean(); 00552 smartcards.Shutdown(); 00553 keys.SafeClear(); 00554 } 00555 00556 // --- cMenuInfoSc ------------------------------------------------------------- 00557 00558 class cMenuInfoSc : public cOsdMenu { 00559 public: 00560 cMenuInfoSc(void); 00561 virtual eOSState ProcessKey(eKeys Key); 00562 }; 00563 00564 cMenuInfoSc::cMenuInfoSc(void) 00565 :cOsdMenu(tr("SoftCAM"),25) 00566 { 00567 Add(new cScInfoItem(tr("Current keys:"))); 00568 int d=0, n; 00569 do { 00570 n=0; 00571 char *ks; 00572 do { 00573 const char *id; 00574 if((ks=cGlobal::CurrKeyStr(d,n,&id))) { 00575 char buffer[32]; 00576 snprintf(buffer,sizeof(buffer)," [%s.%d]",id,n); 00577 Add(new cScInfoItem(buffer,ks)); 00578 free(ks); 00579 n++; 00580 } 00581 } while(ks); 00582 d++; 00583 } while(n>0); 00584 if(Feature.KeyFile()) { 00585 Add(new cScInfoItem(tr("Key update status:"))); 00586 int fk, nk; 00587 cSystem::KeyStats(fk,nk); 00588 // TRANSLATORS: 2 leading spaces! 00589 Add(new cScInfoItem(tr(" [Seen keys]"),fk)); 00590 // TRANSLATORS: 2 leading spaces! 00591 Add(new cScInfoItem(tr(" [New keys]"), nk)); 00592 } 00593 Display(); 00594 } 00595 00596 eOSState cMenuInfoSc::ProcessKey(eKeys Key) 00597 { 00598 eOSState state=cOsdMenu::ProcessKey(Key); 00599 if(state==osUnknown && Key==kOk) state=osBack; 00600 return state; 00601 } 00602 00603 // --- cMenuInfoCard ----------------------------------------------------------- 00604 00605 class cMenuInfoCard : public cMenuText { 00606 private: 00607 int port; 00608 char infoStr[4096]; 00609 public: 00610 cMenuInfoCard(int Port); 00611 virtual eOSState ProcessKey(eKeys Key); 00612 }; 00613 00614 cMenuInfoCard::cMenuInfoCard(int Port) 00615 :cMenuText(tr("Smartcard"),0,fontFix) 00616 { 00617 port=Port; 00618 smartcards.CardInfo(port,infoStr,sizeof(infoStr)); 00619 SetText(infoStr); 00620 SetHelp(tr("Reset card")); 00621 Display(); 00622 } 00623 00624 eOSState cMenuInfoCard::ProcessKey(eKeys Key) 00625 { 00626 if(Key==kRed && Interface->Confirm(tr("Really reset card?"))) { 00627 smartcards.CardReset(port); 00628 return osEnd; 00629 } 00630 eOSState state=cMenuText::ProcessKey(Key); 00631 if(state==osUnknown) state=osContinue; 00632 return state; 00633 } 00634 00635 // --- cLogOptItem ------------------------------------------------------------- 00636 00637 class cLogOptItem : public cMenuEditBoolItem { 00638 private: 00639 int o; 00640 public: 00641 cLogOptItem(const char *Name, int O, int *val); 00642 int Option(void) { return o; } 00643 }; 00644 00645 cLogOptItem::cLogOptItem(const char *Name, int O, int *val) 00646 :cMenuEditBoolItem(Name,val) 00647 { 00648 o=O; 00649 } 00650 00651 // --- cMenuLogMod ------------------------------------------------------------- 00652 00653 class cMenuLogMod : public cOsdMenu { 00654 private: 00655 int m; 00656 int v[LOPT_NUM], cfg[LOPT_NUM]; 00657 // 00658 void Store(void); 00659 public: 00660 cMenuLogMod(int M); 00661 virtual eOSState ProcessKey(eKeys Key); 00662 }; 00663 00664 cMenuLogMod::cMenuLogMod(int M) 00665 :cOsdMenu(tr("Module config"),33) 00666 { 00667 m=M; 00668 Add(new cOsdItem(tr("Reset module to default"),osUser9)); 00669 const char *name=cLogging::GetModuleName(LCLASS(m,0)); 00670 int o=cLogging::GetModuleOptions(LCLASS(m,0)); 00671 if(o>=0) { 00672 for(int i=0; i<LOPT_NUM; i++) { 00673 const char *opt; 00674 if(i==0) opt="enable"; 00675 else opt=cLogging::GetOptionName(LCLASS(m,1<<i)); 00676 if(opt) { 00677 char buff[64]; 00678 snprintf(buff,sizeof(buff),"%s.%s",name,opt); 00679 cfg[i]=(o&(1<<i)) ? 1:0; 00680 v[i]=1; 00681 Add(new cLogOptItem(buff,i,&cfg[i])); 00682 } 00683 else v[i]=0; 00684 } 00685 } 00686 Display(); 00687 } 00688 00689 void cMenuLogMod::Store(void) 00690 { 00691 int o=0; 00692 for(int i=0; i<LOPT_NUM; i++) if(v[i] && cfg[i]) o|=(1<<i); 00693 cLogging::SetModuleOptions(LCLASS(m,o)); 00694 ScSetup.Store(false); 00695 } 00696 00697 eOSState cMenuLogMod::ProcessKey(eKeys Key) 00698 { 00699 eOSState state=cOsdMenu::ProcessKey(Key); 00700 switch(state) { 00701 case osUser9: 00702 if(Interface->Confirm(tr("Really reset module to default?"))) { 00703 cLogging::SetModuleDefault(LCLASS(m,0)); 00704 ScSetup.Store(false); state=osBack; 00705 } 00706 break; 00707 00708 case osContinue: 00709 if(NORMALKEY(Key)==kLeft || NORMALKEY(Key)==kRight) { 00710 cLogOptItem *item=dynamic_cast<cLogOptItem *>(Get(Current())); 00711 if(item) { 00712 int o=item->Option(); 00713 cLogging::SetModuleOption(LCLASS(m,1<<o),cfg[o]); 00714 } 00715 } 00716 break; 00717 00718 case osUnknown: 00719 if(Key==kOk) { Store(); state=osBack; } 00720 break; 00721 00722 default: 00723 break; 00724 } 00725 return state; 00726 } 00727 00728 // --- cLogModItem ------------------------------------------------------------- 00729 00730 class cLogModItem : public cOsdItem { 00731 private: 00732 int m; 00733 public: 00734 cLogModItem(const char *Name, int M); 00735 int Module(void) { return m; } 00736 }; 00737 00738 cLogModItem::cLogModItem(const char *Name, int M) 00739 :cOsdItem(osUnknown) 00740 { 00741 m=M; 00742 char buf[64]; 00743 snprintf(buf,sizeof(buf),"%s '%s'...",tr("Module"),Name); 00744 SetText(buf,true); 00745 } 00746 00747 // --- cMenuLogSys ------------------------------------------------------------- 00748 00749 class cMenuLogSys : public cOsdMenu { 00750 private: 00751 void Store(void); 00752 public: 00753 cMenuLogSys(void); 00754 virtual eOSState ProcessKey(eKeys Key); 00755 }; 00756 00757 cMenuLogSys::cMenuLogSys(void) 00758 :cOsdMenu(tr("Message logging"),33) 00759 { 00760 LogOpts->Backup(); LogOpts->Create(this); 00761 Add(new cOsdItem(tr("Disable ALL modules"),osUser9)); 00762 Add(new cOsdItem(tr("Reset ALL modules to default"),osUser8)); 00763 for(int m=1; m<LMOD_MAX; m++) { 00764 const char *name=cLogging::GetModuleName(LCLASS(m,0)); 00765 if(name) 00766 Add(new cLogModItem(name,m)); 00767 } 00768 Display(); 00769 } 00770 00771 void cMenuLogSys::Store(void) 00772 { 00773 char *lf=strdup(logcfg.logFilename); 00774 ScSetup.Store(false); 00775 if(!lf || strcmp(lf,logcfg.logFilename)) 00776 cLogging::ReopenLogfile(); 00777 free(lf); 00778 } 00779 00780 eOSState cMenuLogSys::ProcessKey(eKeys Key) 00781 { 00782 eOSState state=cOsdMenu::ProcessKey(Key); 00783 switch(state) { 00784 case osUser9: 00785 if(Interface->Confirm(tr("Really disable ALL modules?"))) { 00786 for(int m=1; m<LMOD_MAX; m++) 00787 cLogging::SetModuleOption(LCLASS(m,LMOD_ENABLE),false); 00788 Store(); state=osBack; 00789 } 00790 break; 00791 00792 case osUser8: 00793 if(Interface->Confirm(tr("Really reset ALL modules to default?"))) { 00794 for(int m=1; m<LMOD_MAX; m++) 00795 cLogging::SetModuleDefault(LCLASS(m,0)); 00796 Store(); state=osBack; 00797 } 00798 break; 00799 00800 case osUnknown: 00801 if(Key==kOk) { 00802 cLogModItem *item=dynamic_cast<cLogModItem *>(Get(Current())); 00803 if(item) state=AddSubMenu(new cMenuLogMod(item->Module())); 00804 else { Store(); state=osBack; } 00805 } 00806 break; 00807 00808 default: 00809 break; 00810 } 00811 return state; 00812 } 00813 00814 // --- cMenuSysOpts ------------------------------------------------------------- 00815 00816 class cMenuSysOpts : public cOsdMenu { 00817 public: 00818 cMenuSysOpts(void); 00819 virtual eOSState ProcessKey(eKeys Key); 00820 }; 00821 00822 cMenuSysOpts::cMenuSysOpts(void) 00823 :cOsdMenu(tr("Cryptsystem options"),33) 00824 { 00825 for(cOpts *opts=0; (opts=cSystems::GetSystemOpts(opts==0));) { 00826 opts->Backup(); 00827 opts->Create(this); 00828 } 00829 Display(); 00830 } 00831 00832 eOSState cMenuSysOpts::ProcessKey(eKeys Key) 00833 { 00834 eOSState state=cOsdMenu::ProcessKey(Key); 00835 switch(state) { 00836 case osContinue: 00837 if(NORMALKEY(Key)==kUp || NORMALKEY(Key)==kDown) { 00838 cOsdItem *item=Get(Current()); 00839 if(item) item->ProcessKey(kNone); 00840 } 00841 break; 00842 00843 case osUnknown: 00844 if(Key==kOk) { ScSetup.Store(false); state=osBack; } 00845 break; 00846 00847 default: 00848 break; 00849 } 00850 return state; 00851 } 00852 00853 // --- cMenuSetupSc ------------------------------------------------------------ 00854 00855 class cMenuSetupSc : public cMenuSetupPage { 00856 private: 00857 char *cfgdir; 00858 protected: 00859 virtual void Store(void); 00860 public: 00861 cMenuSetupSc(const char *CfgDir); 00862 virtual ~cMenuSetupSc(); 00863 virtual eOSState ProcessKey(eKeys Key); 00864 }; 00865 00866 cMenuSetupSc::cMenuSetupSc(const char *CfgDir) 00867 { 00868 cfgdir=strdup(CfgDir); 00869 SetSection(tr("SoftCAM")); 00870 00871 ScOpts->Backup(); LogOpts->Backup(); 00872 for(cOpts *opts=0; (opts=cSystems::GetSystemOpts(opts==0));) opts->Backup(); 00873 00874 ScOpts->Create(this); 00875 Add(new cOsdItem(tr("Cryptsystem options..."),osUser5)); 00876 Add(new cOsdItem(tr("Message logging..."),osUser6)); 00877 if(Feature.SmartCard()) { 00878 char id[IDSTR_LEN]; 00879 for(int i=0; smartcards.ListCard(i,id,sizeof(id)); i++) { 00880 char buff[32]; 00881 snprintf(buff,sizeof(buff),"%s %d",tr("Smartcard interface"),i); 00882 cScInfoItem *ii; 00883 if(id[0]) ii=new cScInfoItem(buff,id,osUser4); 00884 else ii=new cScInfoItem(buff,tr("(empty)")); 00885 ii->Ident(i); 00886 Add(ii); 00887 } 00888 } 00889 Add(new cOsdItem(tr("Status information..."),osUser8)); 00890 Add(new cOsdItem(tr("Flush ECM cache"),osUser7)); 00891 Add(new cOsdItem(tr("Reload files"),osUser9)); 00892 } 00893 00894 cMenuSetupSc::~cMenuSetupSc() 00895 { 00896 free(cfgdir); 00897 } 00898 00899 void cMenuSetupSc::Store(void) 00900 { 00901 ScSetup.Store(false); 00902 } 00903 00904 eOSState cMenuSetupSc::ProcessKey(eKeys Key) 00905 { 00906 eOSState state = cOsdMenu::ProcessKey(Key); 00907 switch(state) { 00908 case osUser4: 00909 if(Feature.SmartCard()) { 00910 cScInfoItem *ii=dynamic_cast<cScInfoItem *>(Get(Current())); 00911 if(ii) return(AddSubMenu(new cMenuInfoCard(ii->Ident()))); 00912 } 00913 state=osContinue; 00914 break; 00915 00916 case osUser7: 00917 state=osContinue; 00918 if(Interface->Confirm(tr("Really flush ECM cache?"))) { 00919 ecmcache.Flush(); 00920 state=osEnd; 00921 } 00922 break; 00923 00924 case osUser8: 00925 return AddSubMenu(new cMenuInfoSc); 00926 00927 case osUser6: 00928 return AddSubMenu(new cMenuLogSys); 00929 00930 case osUser5: 00931 return AddSubMenu(new cMenuSysOpts); 00932 00933 case osUser9: 00934 state=osContinue; 00935 if(!cGlobal::Active(true)) { 00936 if(Interface->Confirm(tr("Really reload files?"))) { 00937 Store(); 00938 cSoftCAM::Load(cfgdir); 00939 state=osEnd; 00940 } 00941 } 00942 else 00943 Skins.Message(mtError,tr("Active! Can't reload files now")); 00944 break; 00945 00946 case osContinue: 00947 if(NORMALKEY(Key)==kUp || NORMALKEY(Key)==kDown) { 00948 cOsdItem *item=Get(Current()); 00949 if(item) item->ProcessKey(kNone); 00950 } 00951 break; 00952 00953 case osUnknown: 00954 if(Key==kOk) { Store(); state=osBack; } 00955 break; 00956 00957 default: 00958 break; 00959 } 00960 return state; 00961 } 00962 00963 // --- cScSetup --------------------------------------------------------------- 00964 00965 cScSetup ScSetup; 00966 00967 cScSetup::cScSetup(void) 00968 { 00969 AutoUpdate=1; 00970 memset(ScCaps,0,sizeof(ScCaps)); 00971 ScCaps[0]=1; 00972 ScCaps[1]=2; 00973 ConcurrentFF=0; 00974 LocalPriority=0; 00975 ForceTransfer=1; 00976 PrestartAU=0; 00977 SuperKeys=0; 00978 EcmCache=0; 00979 DeCsaTsBuffSize=4; 00980 } 00981 00982 void cScSetup::Check(void) 00983 { 00984 if(AutoUpdate==0) 00985 PRINTF(L_GEN_WARN,"Keys updates (AU) are disabled."); 00986 for(int i=0; i<MAXSCCAPS; i++) 00987 if(ScCaps[i]>=16) { 00988 PRINTF(L_GEN_WARN,"ScCaps contains unusual value. Check your config! (You can ignore this message if you have more than 16 dvb cards in your system ;)"); 00989 break; 00990 } 00991 00992 PRINTF(L_CORE_LOAD,"** Plugin config:"); 00993 PRINTF(L_CORE_LOAD,"** Key updates (AU) are %s (%sprestart)",AutoUpdate?(AutoUpdate==1?"enabled (active CAIDs)":"enabled (all CAIDs)"):"DISABLED",PrestartAU?"":"no "); 00994 PRINTF(L_CORE_LOAD,"** Local systems %stake priority over cached remote",LocalPriority?"":"DON'T "); 00995 PRINTF(L_CORE_LOAD,"** Concurrent FF recordings are %sallowed",ConcurrentFF?"":"NOT "); 00996 PRINTF(L_CORE_LOAD,"** %sorce transfermode with digital audio",ForceTransfer?"F":"DON'T f"); 00997 PRINTF(L_CORE_LOAD,"** ECM cache is set to %s",EcmCache ? (EcmCache==1?"READ-ONLY":"DISABLED"):"enabled"); 00998 PRINTF(L_CORE_LOAD,"** TsBufferSize is %d MB",DeCsaTsBuffSize); 00999 LBSTART(L_CORE_LOAD); 01000 LBPUT("** ScCaps are"); for(int i=0; i<MAXSCCAPS ; i++) LBPUT(" %d",ScCaps[i]); 01001 LBEND(); 01002 } 01003 01004 void cScSetup::Store(bool AsIs) 01005 { 01006 if(ScOpts) ScOpts->Store(AsIs); 01007 cSystems::ConfigStore(AsIs); 01008 if(LogOpts) LogOpts->Store(AsIs); 01009 cLineBuff lb(128); 01010 if(cLogging::GetConfig(&lb)) 01011 ScPlugin->SetupStore("LogConfig",lb.Line()); 01012 } 01013 01014 bool cScSetup::CapCheck(int n) 01015 { 01016 for(int j=0; j<MAXSCCAPS; j++) 01017 if(ScCaps[j] && ScCaps[j]==n+1) return true; 01018 return false; 01019 } 01020 01021 // --- cScHousekeeper ---------------------------------------------------------- 01022 01023 class cScHousekeeper : public cThread { 01024 protected: 01025 virtual void Action(void); 01026 public: 01027 cScHousekeeper(void); 01028 ~cScHousekeeper(); 01029 }; 01030 01031 cScHousekeeper::cScHousekeeper(void) 01032 :cThread("SC housekeeper") 01033 { 01034 Start(); 01035 } 01036 01037 cScHousekeeper::~cScHousekeeper() 01038 { 01039 Cancel(3); 01040 } 01041 01042 void cScHousekeeper::Action(void) 01043 { 01044 int c=0; 01045 while(Running()) { 01046 if(++c==20) { 01047 c=0; 01048 cGlobal::HouseKeeping(); 01049 } 01050 if(Feature.KeyFile()) keys.HouseKeeping(); 01051 if(!cGlobal::Active(false)) cStructLoaders::Purge(); 01052 cStructLoaders::Load(true); 01053 cStructLoaders::Save(); 01054 cCondWait::SleepMs(987); 01055 } 01056 } 01057 01058 #ifndef STATICBUILD 01059 01060 // --- cScDll ------------------------------------------------------------------ 01061 01062 class cScDll : public cSimpleItem { 01063 private: 01064 char *fileName; 01065 void *handle; 01066 public: 01067 cScDll(const char *FileName); 01068 ~cScDll(); 01069 bool Load(bool check); 01070 }; 01071 01072 cScDll::cScDll(const char *FileName) 01073 { 01074 fileName=strdup(FileName); 01075 handle=0; 01076 } 01077 01078 cScDll::~cScDll() 01079 { 01080 if(handle) dlclose(handle); 01081 free(fileName); 01082 } 01083 01084 bool cScDll::Load(bool check) 01085 { 01086 char *base=rindex(fileName,'/'); 01087 if(base) base++; else base=fileName; 01088 PRINTF(L_CORE_DYN,"loading library: %s",base); 01089 if(!handle) { 01090 handle=dlopen(fileName,RTLD_NOW|(check?RTLD_LOCAL:RTLD_GLOBAL)); 01091 if(handle) { 01092 if(!check) return true; 01093 dlerror(); 01094 int *libapivers=(int *)dlsym(handle,"ScLibApiVersion"); 01095 const char *error=dlerror(); 01096 if(!error && *libapivers==SCAPIVERS) return true; 01097 else PRINTF(L_GEN_ERROR,"dload: %s: SCAPI version doesn't match (plugin=%d, library=%d)",base,SCAPIVERS,!error?*libapivers:0); 01098 } 01099 else PRINTF(L_GEN_ERROR,"dload: %s: %s",base,dlerror()); 01100 } 01101 return false; 01102 } 01103 01104 // --- cScDlls ----------------------------------------------------------------- 01105 01106 #define LIBVDR_PREFIX "libvdr-" 01107 #define LIBSC_PREFIX "libsc-" 01108 #define SO_INDICATOR ".so." 01109 01110 class cScDlls : public cSimpleList<cScDll> { 01111 private: 01112 void *handle; 01113 public: 01114 cScDlls(void); 01115 ~cScDlls(); 01116 bool Load(void); 01117 }; 01118 01119 cScDlls::cScDlls(void) 01120 { 01121 handle=0; 01122 } 01123 01124 cScDlls::~cScDlls() 01125 { 01126 Clear(); 01127 if(handle) dlclose(handle); 01128 PRINTF(L_CORE_DYN,"unload done"); 01129 } 01130 01131 bool cScDlls::Load(void) 01132 { 01133 Dl_info info; 01134 static int marker=0; 01135 if(!dladdr((void *)&marker,&info)) { 01136 PRINTF(L_GEN_ERROR,"dladdr: %s",dlerror()); 01137 return false; 01138 } 01139 01140 // we have to re-dlopen our selfs as VDR doesn't use RTLD_GLOBAL 01141 // but our symbols have to be available to the sub libs. 01142 handle=dlopen(info.dli_fname,RTLD_NOW|RTLD_GLOBAL); 01143 if(!handle) { 01144 PRINTF(L_GEN_ERROR,"dlopen myself: %s",dlerror()); 01145 return false; 01146 } 01147 01148 char *path=strdup(info.dli_fname); 01149 char *p; 01150 if((p=rindex(path,'/'))) *p=0; 01151 PRINTF(L_CORE_DYN,"library path %sn",path); 01152 01153 char pat[64]; 01154 #if APIVERSNUM >= 10711 01155 #ifdef WITH_SDDVB 01156 { 01157 snprintf(pat,sizeof(pat),"%s%s%s%s",LIBVDR_PREFIX,"dvbsddevice",SO_INDICATOR,APIVERSION); 01158 cScDll *dll=new cScDll(AddDirectory(path,pat)); 01159 if(dll) { 01160 if(dll->Load(false)) { 01161 PRINTF(L_GEN_INFO,"VDR dvbsddevice plugin loaded as subplugin"); 01162 } 01163 Ins(dll); 01164 } 01165 } 01166 #endif //WITH_SDDVB 01167 #ifdef WITH_HDDVB 01168 { 01169 snprintf(pat,sizeof(pat),"%s%s%s%s",LIBVDR_PREFIX,"dvbhddevice",SO_INDICATOR,APIVERSION); 01170 cScDll *dll=new cScDll(AddDirectory(path,pat)); 01171 if(dll) { 01172 if(dll->Load(false)) { 01173 PRINTF(L_GEN_INFO,"VDR dvbhddevice plugin loaded as subplugin"); 01174 } 01175 Ins(dll); 01176 } 01177 } 01178 #endif //WITH_HDDVB 01179 #endif //APIVERSNUM >= 10711 01180 01181 snprintf(pat,sizeof(pat),"%s*-%d%s%s",LIBSC_PREFIX,SCAPIVERS,SO_INDICATOR,APIVERSION); 01182 bool res=true; 01183 cReadDir dir(path); 01184 struct dirent *e; 01185 while((e=dir.Next())) { 01186 if(!fnmatch(pat,e->d_name,FNM_PATHNAME|FNM_NOESCAPE)) { 01187 cScDll *dll=new cScDll(AddDirectory(path,e->d_name)); 01188 if(dll) { 01189 if(!dll->Load(true)) res=false; 01190 Ins(dll); 01191 } 01192 } 01193 } 01194 free(path); 01195 return res; 01196 } 01197 01198 #endif //STATICBUILD 01199 01200 // --- cScPlugin --------------------------------------------------------------- 01201 01202 class cScPlugin : public cPlugin { 01203 private: 01204 #ifndef STATICBUILD 01205 cScDlls dlls; 01206 #endif 01207 cScHousekeeper *keeper; 01208 bool dllSuccess; 01209 public: 01210 cScPlugin(void); 01211 virtual ~cScPlugin(); 01212 virtual const char *Version(void); 01213 virtual const char *Description(void); 01214 virtual const char *CommandLineHelp(void); 01215 virtual bool ProcessArgs(int argc, char *argv[]); 01216 virtual bool Initialize(void); 01217 virtual bool Start(void); 01218 virtual void Stop(void); 01219 #ifndef SASC 01220 virtual void MainThreadHook(void); 01221 #endif 01222 virtual cMenuSetupPage *SetupMenu(void); 01223 virtual bool SetupParse(const char *Name, const char *Value); 01224 virtual const char **SVDRPHelpPages(void); 01225 virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); 01226 }; 01227 01228 cScPlugin::cScPlugin(void) 01229 { 01230 static const char *logg[] = { trNOOP("off"),trNOOP("active CAIDs"),trNOOP("all CAIDs") }; 01231 static const char *skey[] = { trNOOP("comment out"),trNOOP("remove") }; 01232 static const char *ecache[] = { trNOOP("enabled"),trNOOP("read-only"),trNOOP("off") }; 01233 ScOpts=new cOpts(0,10); 01234 ScOpts->Add(new cOptSel ("AutoUpdate" ,trNOOP("Update keys (AU)") ,&ScSetup.AutoUpdate,3,logg)); 01235 ScOpts->Add(new cOptBool ("PrestartAU" ,trNOOP("Start AU on EPG scan") ,&ScSetup.PrestartAU)); 01236 ScOpts->Add(new cOptSel ("SuperKeys" ,trNOOP("Superseded keys") ,&ScSetup.SuperKeys,2,skey)); 01237 ScOpts->Add(new cOptBool ("ConcurrentFF" ,trNOOP("Concurrent FF streams"),&ScSetup.ConcurrentFF)); 01238 ScOpts->Add(new cOptBool ("ForceTranfer" ,trNOOP("Force TransferMode") ,&ScSetup.ForceTransfer)); 01239 ScOpts->Add(new cOptBool ("LocalPriority",trNOOP("Prefer local systems") ,&ScSetup.LocalPriority)); 01240 ScOpts->Add(new cOptSel ("EcmCache" ,trNOOP("ECM cache") ,&ScSetup.EcmCache,3,ecache)); 01241 ScOpts->Add(new cOptInt ("DeCsaTsBuffSize",trNOOP("TS buffer size MB") ,&ScSetup.DeCsaTsBuffSize,4,15)); 01242 ScOpts->Add(new cOptMInt ("ScCaps" ,trNOOP("Active on DVB card") , ScSetup.ScCaps,MAXSCCAPS,0)); 01243 LogOpts=new cOpts(0,6); 01244 LogOpts->Add(new cOptBool ("LogConsole" ,trNOOP("Log to console") ,&logcfg.logCon)); 01245 LogOpts->Add(new cOptBool ("LogFile" ,trNOOP("Log to file") ,&logcfg.logFile)); 01246 LogOpts->Add(new cOptStr ("LogFileName" ,trNOOP("Filename") ,logcfg.logFilename,sizeof(logcfg.logFilename),FileNameChars)); 01247 LogOpts->Add(new cOptInt ("LogFileLimit",trNOOP("Filesize limit (KB)") ,&logcfg.maxFilesize,0,2000000)); 01248 LogOpts->Add(new cOptBool ("LogSyslog" ,trNOOP("Log to syslog") ,&logcfg.logSys)); 01249 LogOpts->Add(new cOptBool ("LogUserMsg" ,trNOOP("Show user messages") ,&logcfg.logUser)); 01250 #ifndef STATICBUILD 01251 dllSuccess=dlls.Load(); 01252 #else 01253 dllSuccess=true; 01254 #endif 01255 if(dllSuccess) cScDevices::OnPluginLoad(); 01256 keeper=0; 01257 } 01258 01259 cScPlugin::~cScPlugin() 01260 { 01261 delete keeper; 01262 delete ScOpts; 01263 delete LogOpts; 01264 cScDevices::OnPluginUnload(); 01265 } 01266 01267 bool cScPlugin::Initialize(void) 01268 { 01269 PRINTF(L_GEN_INFO,"SC version %s initializing (VDR %s)",ScVersion,VDRVERSION); 01270 return dllSuccess && cScDevices::Initialize(); 01271 } 01272 01273 bool cScPlugin::Start(void) 01274 { 01275 PRINTF(L_GEN_INFO,"SC version %s starting (VDR %s)",ScVersion,VDRVERSION); 01276 if(APIVERSNUM<MINAPIVERSNUM) { 01277 PRINTF(L_GEN_ERROR,"SC plugin needs at least VDR API version %d.%d.%d",MIN_VERS,MIN_MAJOR,MIN_MINOR); 01278 return false; 01279 } 01280 if(sizeof(int)!=4) { 01281 PRINTF(L_GEN_ERROR,"compiled with 'int' as %d bit. Only supporting 32 bit.",(int)sizeof(int)*8); 01282 return false; 01283 } 01284 if(sizeof(long long)!=8) { 01285 PRINTF(L_GEN_ERROR,"compiled with 'long long' as %d bit. Only supporting 64 bit.",(int)sizeof(long long)*8); 01286 return false; 01287 } 01288 01289 ScPlugin=this; 01290 const char *cfgdir=ConfigDirectory(cfgsub); 01291 filemaps.SetCfgDir(cfgdir); 01292 cStructLoaders::SetCfgDir(cfgdir); 01293 ScSetup.Check(); 01294 if(!cSoftCAM::Load(cfgdir)) return false; 01295 cScDevices::Startup(); 01296 keeper=new cScHousekeeper; 01297 return true; 01298 } 01299 01300 void cScPlugin::Stop(void) 01301 { 01302 delete keeper; keeper=0; 01303 cScDevices::Shutdown(); 01304 LogStatsDown(); 01305 cSoftCAM::Shutdown(); 01306 PRINTF(L_GEN_DEBUG,"SC cleanup done"); 01307 } 01308 01309 const char *cScPlugin::Version(void) 01310 { 01311 return ScVersion; 01312 } 01313 01314 const char *cScPlugin::Description(void) 01315 { 01316 return tr("A software emulated CAM"); 01317 } 01318 01319 const char *cScPlugin::CommandLineHelp(void) 01320 { 01321 static char *help_str=0; 01322 01323 free(help_str); // for easier orientation, this is column 80| 01324 help_str=bprintf( " -B N --budget=N forces DVB device N to budget mode (using FFdecsa)\n" 01325 " -E CMD --external-au=CMD script for external key updates\n" 01326 ); 01327 return help_str; 01328 } 01329 01330 bool cScPlugin::ProcessArgs(int argc, char *argv[]) 01331 { 01332 static struct option long_options[] = { 01333 { "external-au", required_argument, NULL, 'E' }, 01334 { "budget", required_argument, NULL, 'B' }, 01335 { NULL } 01336 }; 01337 01338 int c, option_index=0; 01339 while((c=getopt_long(argc,argv,"B:E:",long_options,&option_index))!=-1) { 01340 switch (c) { 01341 case 'E': externalAU=optarg; break; 01342 case 'B': cScDevices::SetForceBudget(atoi(optarg)); break; 01343 default: return false; 01344 } 01345 } 01346 return true; 01347 } 01348 01349 cMenuSetupPage *cScPlugin::SetupMenu(void) 01350 { 01351 return new cMenuSetupSc(ConfigDirectory(cfgsub)); 01352 } 01353 01354 bool cScPlugin::SetupParse(const char *Name, const char *Value) 01355 { 01356 if((ScOpts && ScOpts->Parse(Name,Value)) || 01357 (LogOpts && LogOpts->Parse(Name,Value)) || 01358 cSystems::ConfigParse(Name,Value)) ; 01359 else if(!strcasecmp(Name,"LogConfig")) cLogging::ParseConfig(Value); 01360 else return false; 01361 return true; 01362 } 01363 01364 #ifndef SASC 01365 01366 void cScPlugin::MainThreadHook(void) 01367 { 01368 int n=0; 01369 cUserMsg *um; 01370 while(++n<=10 && (um=ums.GetQueuedMsg())) { 01371 Skins.QueueMessage(mtInfo,um->Message()); 01372 delete um; 01373 } 01374 } 01375 01376 #endif //SASC 01377 01378 const char **cScPlugin::SVDRPHelpPages(void) 01379 { 01380 static const char *HelpPages[] = { 01381 "RELOAD\n" 01382 " Reload all configuration files.", 01383 "KEY <string>\n", 01384 " Add key to the key database (as if it was received from EMM stream).", 01385 "LOG <on|off> <class>[,<class>...]\n" 01386 " Turn the given message class(es) on or off.", 01387 "LOGCFG\n" 01388 " Display available message classes and their status.", 01389 "LOGFILE <on|off> [<filename>]\n" 01390 " Enables/disables logging to file and optionaly sets the filename.", 01391 NULL 01392 }; 01393 return HelpPages; 01394 } 01395 01396 cString cScPlugin::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) 01397 { 01398 if(!strcasecmp(Command,"RELOAD")) { 01399 if(cGlobal::Active(true)) { 01400 ReplyCode=550; 01401 return "Softcam active. Can't reload files now"; 01402 } 01403 else { 01404 if(cSoftCAM::Load(ConfigDirectory(cfgsub))) 01405 return "Files reloaded successfully"; 01406 else { 01407 ReplyCode=901; 01408 return "Reloading files not entirely successfull"; 01409 } 01410 } 01411 } 01412 else if(!strcasecmp(Command,"KEY")) { 01413 if(Option && *Option) { 01414 if(keys.NewKeyParse(skipspace(Option),"from SVDR")) 01415 return "Key update successfull"; 01416 else { 01417 ReplyCode=901; 01418 return "Key already known or invalid key format"; 01419 } 01420 } 01421 else { ReplyCode=501; return "Missing args"; } 01422 } 01423 else if(!strcasecmp(Command,"LOG")) { 01424 if(Option && *Option) { 01425 char tmp[1024]; 01426 strn0cpy(tmp,Option,sizeof(tmp)); 01427 char *opt=tmp; 01428 opt=skipspace(opt); 01429 bool mode; 01430 if(!strncasecmp(opt,"ON ",3)) { mode=true; opt+=3; } 01431 else if(!strncasecmp(opt,"OFF ",4)) { mode=false; opt+=4; } 01432 else { ReplyCode=501; return "Bad mode, valid: on off"; } 01433 do { 01434 char *s=index(opt,','); 01435 if(s) *s++=0; 01436 int c=cLogging::GetClassByName(opt); 01437 if(c>=0) cLogging::SetModuleOption(c,mode); 01438 else { ReplyCode=501; return "Unknown message class"; } 01439 opt=s; 01440 } while(opt); 01441 ScSetup.Store(true); 01442 Setup.Save(); 01443 return "Done"; 01444 } 01445 else { ReplyCode=501; return "Missing args"; } 01446 } 01447 else if(!strcasecmp(Command,"LOGCFG")) { 01448 cLineBuff lb(256); 01449 for(int m=1; m<LMOD_MAX; m++) { 01450 const char *name=cLogging::GetModuleName(LCLASS(m,0)); 01451 if(name) { 01452 int o=cLogging::GetModuleOptions(LCLASS(m,0)); 01453 if(o>=0) { 01454 for(int i=0; i<LOPT_NUM; i++) { 01455 const char *opt; 01456 if(i==0) opt="enable"; 01457 else opt=cLogging::GetOptionName(LCLASS(m,1<<i)); 01458 if(opt) 01459 lb.Printf("%s.%s %s\n",name,opt,(o&(1<<i))?"on":"off"); 01460 } 01461 } 01462 } 01463 } 01464 if(lb.Length()>0) return lb.Line(); 01465 ReplyCode=901; return "No config available"; 01466 } 01467 else if(!strcasecmp(Command,"LOGFILE")){ 01468 if(Option && *Option) { 01469 char tmp[1024]; 01470 strn0cpy(tmp,Option,sizeof(tmp)); 01471 char *opt=tmp; 01472 opt=skipspace(opt); 01473 bool mode; 01474 if(!strncasecmp(opt,"ON",2)) { mode=true; opt+=2; } 01475 else if(!strncasecmp(opt,"OFF",3)) { mode=false; opt+=3; } 01476 else { ReplyCode=501; return "Bad mode, valid: on off"; } 01477 cLineBuff lb(256); 01478 if(mode) { 01479 logcfg.logFile=true; 01480 if(*opt==' ' || *opt=='\t') { 01481 opt=stripspace(skipspace(opt)); 01482 strn0cpy(logcfg.logFilename,opt,sizeof(logcfg.logFilename)); 01483 } 01484 lb.Printf("logging to file enabled, file %s",logcfg.logFilename); 01485 } 01486 else { 01487 logcfg.logFile=false; 01488 lb.Printf("logging to file disabled"); 01489 } 01490 ScSetup.Store(true); 01491 Setup.Save(); 01492 return lb.Line(); 01493 } 01494 else { ReplyCode=501; return "Missing args"; } 01495 } 01496 return NULL; 01497 } 01498 01499 VDRPLUGINCREATOR(cScPlugin); // Don't touch this!