SASC-NG
DVBSoftCAM

sc.c

Go to the documentation of this file.
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!
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines