SASC
DVBSoftCAM

data.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 <ctype.h>
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 #include <sys/mman.h>
00026 #include <sys/stat.h>
00027 
00028 #include "data.h"
00029 #include "override.h"
00030 #include "misc.h"
00031 #include "scsetup.h"
00032 #include "log-core.h"
00033 #include "i18n.h"
00034 
00035 #define KEY_FILE     "SoftCam.Key"
00036 #define EXT_AU_INT   (15*60*1000) // ms interval for external AU
00037 #define EXT_AU_MIN   ( 2*60*1000) // ms min. interval for external AU
00038 
00039 // -- cFileMap -----------------------------------------------------------------
00040 
00041 cFileMap::cFileMap(const char *Filename, bool Rw)
00042 {
00043   filename=strdup(Filename);
00044   rw=Rw;
00045   fd=-1; count=len=0; addr=0; failed=false;
00046 }
00047 
00048 cFileMap::~cFileMap()
00049 {
00050   Clean();
00051   free(filename);
00052 }
00053 
00054 bool cFileMap::IsFileMap(const char *Name, bool Rw)
00055 {
00056   return (!strcmp(Name,filename) && (!Rw || rw));
00057 }
00058 
00059 void cFileMap::Clean(void)
00060 {
00061   if(addr) { munmap(addr,len); addr=0; len=0; }
00062   if(fd>=0) { close(fd); fd=-1; }
00063 }
00064 
00065 bool cFileMap::Map(void)
00066 {
00067   cMutexLock lock(this);
00068   if(addr) { count++; return true; }
00069   if(!failed) {
00070     struct stat64 ds;
00071     if(!stat64(filename,&ds)) {
00072       if(S_ISREG(ds.st_mode)) {
00073         fd=open(filename,rw ? O_RDWR : O_RDONLY);
00074         if(fd>=0) {
00075           unsigned char *map=(unsigned char *)mmap(0,ds.st_size,rw ? (PROT_READ|PROT_WRITE):(PROT_READ),MAP_SHARED,fd,0);
00076           if(map!=MAP_FAILED) {
00077             addr=map; len=ds.st_size; count=1;
00078             return true;
00079             }
00080           else PRINTF(L_GEN_ERROR,"mapping failed on %s: %s",filename,strerror(errno));
00081           close(fd); fd=-1;
00082           }
00083         else PRINTF(L_GEN_ERROR,"error opening filemap %s: %s",filename,strerror(errno));
00084         }
00085       else PRINTF(L_GEN_ERROR,"filemap %s is not a regular file",filename);
00086       }
00087     else PRINTF(L_GEN_ERROR,"can't stat filemap %s: %s",filename,strerror(errno));
00088     failed=true; // don't try this one over and over again
00089     }
00090   return false;
00091 }
00092 
00093 bool cFileMap::Unmap(void)
00094 {
00095   cMutexLock lock(this);
00096   if(addr) {
00097     if(!(--count)) { Clean(); return true; }
00098     else Sync();
00099     }
00100   return false;
00101 }
00102 
00103 void cFileMap::Sync(void)
00104 {
00105   cMutexLock lock(this);
00106   if(addr) msync(addr,len,MS_ASYNC);
00107 }
00108 
00109 // -- cFileMaps ----------------------------------------------------------------
00110 
00111 cFileMaps filemaps;
00112 
00113 cFileMaps::cFileMaps(void)
00114 {
00115   cfgDir=0;
00116 }
00117 
00118 cFileMaps::~cFileMaps()
00119 {
00120   Clear();
00121   free(cfgDir);
00122 }
00123 
00124 void cFileMaps::SetCfgDir(const char *CfgDir)
00125 {
00126   free(cfgDir);
00127   cfgDir=strdup(CfgDir);
00128 }
00129 
00130 cFileMap *cFileMaps::GetFileMap(const char *name, const char *domain, bool rw)
00131 {
00132   cMutexLock lock(this);
00133   char path[256];
00134   snprintf(path,sizeof(path),"%s/%s/%s",cfgDir,domain,name);
00135   cFileMap *fm=First();
00136   while(fm) {
00137     if(fm->IsFileMap(path,rw)) return fm;
00138     fm=Next(fm);
00139     }
00140   fm=new cFileMap(path,rw);
00141   Add(fm);
00142   return fm;  
00143 }
00144 
00145 // -- cStructItem --------------------------------------------------------------
00146 
00147 cStructItem::cStructItem(void)
00148 {
00149   comment=0; deleted=special=false;
00150 }
00151 
00152 cStructItem::~cStructItem()
00153 {
00154   free(comment);
00155 }
00156 
00157 void cStructItem::SetComment(const char *com)
00158 {
00159   free(comment);
00160   comment=com ? strdup(com):0;
00161 }
00162 
00163 bool cStructItem::Save(FILE *f)
00164 {
00165   fprintf(f,"%s%s\n",*ToString(false),comment?comment:"");
00166   return ferror(f)==0;
00167 }
00168 
00169 // -- cCommentItem -------------------------------------------------------------
00170 
00171 class cCommentItem : public cStructItem {
00172 public:
00173   cCommentItem(void);
00174   };
00175 
00176 cCommentItem::cCommentItem(void)
00177 {
00178   SetSpecial();
00179 }
00180 
00181 // -- cStructLoader ------------------------------------------------------------
00182 
00183 cStructLoader::cStructLoader(const char *Type, const char *Filename, int Flags)
00184 :lock(true)
00185 {
00186   path=0; mtime=0;
00187   type=Type; filename=Filename; flags=Flags&SL_CUSTOMMASK;
00188   cStructLoaders::Register(this);
00189 }
00190 
00191 cStructLoader::~cStructLoader()
00192 {
00193   free(path);
00194 }
00195 
00196 void cStructLoader::AddItem(cStructItem *n, const char *com, cStructItem *ref)
00197 {
00198   n->SetComment(com);
00199   ListLock(true);
00200   cStructItem *a=0;
00201   if(ref) { // insert before reference
00202     for(a=First(); a; a=Next(a))
00203       if(Next(a)==ref) break;
00204     }
00205   if(!a) { // insert before first non-special
00206     for(a=First(); a;) {
00207       cStructItem *nn=Next(a);
00208       if(nn && !nn->Special()) break;
00209       a=nn;
00210       }
00211     }
00212   Add(n,a);
00213   Modified();
00214   ListUnlock();
00215 }
00216 
00217 void cStructLoader::DelItem(cStructItem *d, bool keep)
00218 {
00219   if(d) {
00220     d->Delete();
00221     if(keep) {
00222       cStructItem *n=new cCommentItem;
00223       n->SetComment(cString::sprintf(";%s%s",*d->ToString(false),d->Comment()?d->Comment():""));
00224       ListLock(true);
00225       Add(n,d);
00226       ListUnlock();
00227       }
00228     Modified();
00229     }
00230 }
00231 
00232 cStructItem *cStructLoader::NextValid(cStructItem *it) const
00233 {
00234   while(it && !it->Valid()) it=Next(it);
00235   return it;
00236 }
00237 
00238 void cStructLoader::SetCfgDir(const char *cfgdir)
00239 {
00240   free(path);
00241   path=strdup(AddDirectory(cfgdir,filename));
00242 }
00243 
00244 time_t cStructLoader::MTime(bool log)
00245 {
00246   struct stat64 st;
00247   if(stat64(path,&st)!=0) {
00248     if(log) {
00249       PRINTF(L_GEN_ERROR,"failed fstat %s: %s",path,strerror(errno));
00250       PRINTF(L_GEN_WARN,"automatic reload of %s disabled",path);
00251       }
00252     st.st_mtime=0;
00253     }
00254   return st.st_mtime;
00255 }
00256 
00257 void cStructLoader::CheckAccess(void)
00258 {
00259   if(access(path,R_OK|W_OK)!=0) {
00260     if(errno!=EACCES)
00261       PRINTF(L_GEN_ERROR,"failed access %s: %s",path,strerror(errno));
00262     PRINTF(L_GEN_WARN,"no write permission on %s. Changes will not be saved!",path);
00263     SL_SETFLAG(SL_NOACCESS);
00264     }
00265   else SL_CLRFLAG(SL_NOACCESS);
00266 }
00267 
00268 bool cStructLoader::CheckUnmodified(void)
00269 {
00270   time_t curr_mtime=MTime(false);
00271   if(mtime && mtime<curr_mtime && SL_TSTFLAG(SL_WATCH)) {
00272      PRINTF(L_CORE_LOAD,"abort save as file %s has been changed externaly",path);
00273      return false;
00274      }
00275   return true;
00276 }
00277 
00278 bool cStructLoader::CheckDoSave(void)
00279 {
00280   return !SL_TSTFLAG(SL_DISABLED) && SL_TSTFLAG(SL_READWRITE)
00281          && !SL_TSTFLAG(SL_NOACCESS) && SL_TSTFLAG(SL_LOADED)
00282          && IsModified() && CheckUnmodified();
00283 }
00284 
00285 void cStructLoader::LoadFinished(void)
00286 {
00287   SL_CLRFLAG(SL_SHUTUP);
00288   if(!SL_TSTFLAG(SL_LOADED))
00289     PRINTF(L_CORE_LOAD,"loading %s terminated with error. Changes will not be saved!",path);
00290 }
00291 
00292 void cStructLoader::OpenFailed(void)
00293 {
00294   if(SL_TSTFLAG(SL_VERBOSE) && !SL_TSTFLAG(SL_SHUTUP)) {
00295     PRINTF(L_GEN_ERROR,"failed open %s: %s",path,strerror(errno));
00296     SL_SETFLAG(SL_SHUTUP);
00297     }
00298   if(SL_TSTFLAG(SL_MISSINGOK)) SL_SETFLAG(SL_LOADED);
00299   else SL_CLRFLAG(SL_LOADED);
00300 }
00301 
00302 void cStructLoader::Load(bool reload)
00303 {
00304   if(SL_TSTFLAG(SL_DISABLED) || (reload && !SL_TSTFLAG(SL_WATCH))) return;
00305   FILE *f=fopen(path,"r");
00306   if(f) {
00307     PreLoad();
00308     int curr_mtime=MTime(true);
00309     ListLock(true);
00310     bool doload=false;
00311     if(!reload) {
00312       Clear(); Modified(false);
00313       mtime=curr_mtime;
00314       doload=true;
00315       }
00316     else if(mtime<curr_mtime) {
00317       PRINTF(L_CORE_LOAD,"detected change of %s",path);
00318       if(IsModified())
00319         PRINTF(L_CORE_LOAD,"discarding in-memory changes");
00320       for(cStructItem *a=First(); a; a=Next(a)) DelItem(a);
00321       Modified(false);
00322       mtime=curr_mtime;
00323       doload=true;
00324       }
00325     if(doload) {
00326       SL_SETFLAG(SL_LOADED);
00327       PRINTF(L_GEN_INFO,"loading %s from %s",type,path);
00328       CheckAccess();
00329       int lineNum=0, num=0;
00330       char buff[4096];
00331       while(fgets(buff,sizeof(buff),f)) {
00332         lineNum++;
00333         if(!index(buff,'\n') && !feof(f)) {
00334           PRINTF(L_GEN_ERROR,"file %s readbuffer overflow line#%d",path,lineNum);
00335           SL_CLRFLAG(SL_LOADED);
00336           break;
00337           }
00338         strreplace(buff,'\n',0); strreplace(buff,'\r',0); // chomp
00339         bool hasContent=false;
00340         char *ls;
00341         for(ls=buff; *ls; ls++) {
00342           if(*ls==';' || *ls=='#') {              // comment
00343             if(hasContent)
00344               while(ls>buff && ls[-1]<=' ') ls--; // search back to non-whitespace
00345             break;
00346             }
00347           if(*ls>' ') hasContent=true;            // line contains something usefull
00348           }
00349         cStructItem *it=0;
00350         if(hasContent) {
00351           char save=*ls;
00352           *ls=0; it=ParseLine(skipspace(buff)); *ls=save;
00353           if(!it) {
00354             PRINTF(L_GEN_ERROR,"file %s has error in line #%d",path,lineNum);
00355             ls=buff;
00356             }
00357           else num++;
00358           }
00359         else ls=buff;
00360         if(!it) it=new cCommentItem;
00361         if(it) {
00362           it->SetComment(ls);
00363           Add(it);
00364           }
00365         else {
00366           PRINTF(L_GEN_ERROR,"out of memory loading file %s",path);
00367           SL_CLRFLAG(SL_LOADED);
00368           break;
00369           }
00370         }
00371       ListUnlock();
00372       PRINTF(L_CORE_LOAD,"loaded %d %s from %s",num,type,path);
00373       PostLoad();
00374       }
00375     else ListUnlock();
00376 
00377     fclose(f);
00378     LoadFinished();
00379     }
00380   else
00381     OpenFailed();
00382 }
00383 
00384 void cStructLoader::Purge(void)
00385 {
00386   if(!SL_TSTFLAG(SL_DISABLED) && !SL_TSTFLAG(SL_NOPURGE)) {
00387     ListLock(true);
00388     for(cStructItem *it=First(); it;) {
00389       cStructItem *n=Next(it);
00390       if(it->Deleted()) Del(it);
00391       it=n;
00392       }
00393     ListUnlock();
00394     }
00395 }
00396 
00397 void cStructLoader::Save(void)
00398 {
00399   if(CheckDoSave()) {
00400     cSafeFile f(path);
00401     if(f.Open()) {
00402       ListLock(false);
00403       for(cStructItem *it=First(); it; it=Next(it))
00404         if(!it->Deleted() && !it->Save(f)) break;
00405       f.Close();
00406       mtime=MTime(true);
00407       Modified(false);
00408       ListUnlock();
00409       PRINTF(L_CORE_LOAD,"saved %s to %s",type,path);
00410       }
00411     }
00412 }
00413 
00414 void cStructLoader::SafeClear(void)
00415 {
00416   ListLock(true); Clear(); ListUnlock();
00417 }
00418 
00419 // -- cStructLoaderPlain -------------------------------------------------------
00420 
00421 cStructLoaderPlain::cStructLoaderPlain(const char *Type, const char *Filename, int Flags)
00422 :cStructLoader(Type,Filename,Flags)
00423 {}
00424 
00425 void cStructLoaderPlain::PreLoad(void)
00426 {
00427   ListLock(true);
00428   Clear(); Modified(false);
00429   ListUnlock();
00430 }
00431 
00432 void cStructLoaderPlain::Load(bool reload)
00433 {
00434   if(SL_TSTFLAG(SL_DISABLED) || reload) return;
00435   FILE *f=fopen(path,"r");
00436   if(f) {
00437     PreLoad();
00438     ListLock(true);
00439     SL_SETFLAG(SL_LOADED);
00440     PRINTF(L_GEN_INFO,"loading %s from %s",type,path);
00441     CheckAccess();
00442     int lineNum=0;
00443     char buff[4096];
00444     while(fgets(buff,sizeof(buff),f)) {
00445       lineNum++;
00446       if(!index(buff,'\n') && !feof(f)) {
00447         PRINTF(L_GEN_ERROR,"file %s readbuffer overflow line#%d",path,lineNum);
00448         SL_CLRFLAG(SL_LOADED);
00449         break;
00450         }
00451       strreplace(buff,'\n',0); strreplace(buff,'\r',0); // chomp
00452       bool hasContent=false;
00453       char *ls;
00454       for(ls=buff; *ls; ls++) {
00455         if(*ls==';' || *ls=='#') break;
00456         if(*ls>' ') hasContent=true;
00457         }
00458       if(hasContent) {
00459         *ls=0;
00460         if(!ParseLinePlain(skipspace(buff)))
00461           PRINTF(L_GEN_ERROR,"file %s has error in line #%d",path,lineNum);
00462         }
00463       }
00464     ListUnlock();
00465     PostLoad();
00466     fclose(f);
00467     LoadFinished();
00468     }
00469   else
00470     OpenFailed();
00471 }
00472 
00473 void cStructLoaderPlain::PreSave(FILE *f)
00474 {
00475   fprintf(f,"## This is a generated file. DO NOT EDIT!!\n"
00476             "## This file will be OVERWRITTEN WITHOUT WARNING!!\n");
00477 }
00478 
00479 void cStructLoaderPlain::Save(void)
00480 {
00481   if(CheckDoSave()) {
00482     cSafeFile f(path);
00483     if(f.Open()) {
00484       ListLock(false);
00485       PreSave(f);
00486       for(cStructItem *it=First(); it; it=Next(it))
00487         if(!it->Deleted() && !it->Save(f)) break;
00488       PostSave(f);
00489       f.Close();
00490       Modified(false);
00491       ListUnlock();
00492       PRINTF(L_CORE_LOAD,"saved %s to %s",type,path);
00493       }
00494     }
00495 }
00496 
00497 // -- cStructLoaders -----------------------------------------------------------
00498 
00499 #define RELOAD_TIMEOUT  20300 // ms
00500 #define PURGE_TIMEOUT   60700 // ms
00501 #define SAVE_TIMEOUT     5000 // ms
00502 
00503 cStructLoader *cStructLoaders::first=0;
00504 cTimeMs cStructLoaders::lastReload;
00505 cTimeMs cStructLoaders::lastPurge;
00506 cTimeMs cStructLoaders::lastSave;
00507 
00508 void cStructLoaders::Register(cStructLoader *ld)
00509 {
00510   PRINTF(L_CORE_DYN,"structloaders: registering loader %s",ld->type);
00511   ld->next=first;
00512   first=ld;
00513 }
00514 
00515 void cStructLoaders::SetCfgDir(const char *cfgdir)
00516 {
00517   for(cStructLoader *ld=first; ld; ld=ld->next)
00518     ld->SetCfgDir(cfgdir);
00519 }
00520 
00521 void cStructLoaders::Load(bool reload)
00522 {
00523   if(!reload || lastReload.TimedOut()) {
00524     for(cStructLoader *ld=first; ld; ld=ld->next) ld->Load(reload);
00525     lastReload.Set(RELOAD_TIMEOUT);
00526     }
00527 }
00528 
00529 void cStructLoaders::Save(bool force)
00530 {
00531   if(force || lastSave.TimedOut()) {
00532     for(cStructLoader *ld=first; ld; ld=ld->next) ld->Save();
00533     lastSave.Set(SAVE_TIMEOUT);
00534     }
00535 }
00536 
00537 void cStructLoaders::Purge(void)
00538 {
00539   if(lastPurge.TimedOut()) {
00540     for(cStructLoader *ld=first; ld; ld=ld->next) ld->Purge();
00541     lastPurge.Set(PURGE_TIMEOUT);
00542     }
00543 }
00544 
00545 // -- cPid ---------------------------------------------------------------------
00546 
00547 cPid::cPid(int Pid, int Section, int Mask)
00548 {
00549   pid=Pid;
00550   sct=Section;
00551   mask=Mask;
00552   filter=0;
00553 }
00554 
00555 // -- cPids --------------------------------------------------------------------
00556 
00557 void cPids::AddPid(int Pid, int Section, int Mask)
00558 {
00559   if(!HasPid(Pid,Section,Mask)) {
00560     cPid *pid=new cPid(Pid,Section,Mask);
00561     Add(pid);
00562     }
00563 }
00564 
00565 bool cPids::HasPid(int Pid, int Section, int Mask)
00566 {
00567   for(cPid *pid=First(); pid; pid=Next(pid))
00568     if(pid->pid==Pid && pid->sct==Section && pid->mask==Mask)
00569       return true;
00570   return false;
00571 }
00572 
00573 // -- cEcmInfo -----------------------------------------------------------------
00574 
00575 cEcmInfo::cEcmInfo(void)
00576 {
00577   Setup();
00578 }
00579 
00580 cEcmInfo::cEcmInfo(const cEcmInfo *e)
00581 {
00582   Setup(); SetName(e->name);
00583   ecm_pid=e->ecm_pid;
00584   ecm_table=e->ecm_table;
00585   caId=e->caId;
00586   emmCaId=e->emmCaId;
00587   provId=e->provId;
00588   AddCaDescr(e);
00589   dataIdx=e->dataIdx;
00590   grPrgId=e->grPrgId; prgId=grPrgId%SIDGRP_SHIFT;
00591   source=e->source;
00592   transponder=e->transponder;
00593   rewriterId=e->rewriterId;
00594   SetRewriter();
00595   dvbAdapter=e->dvbAdapter; dvbFrontend=e->dvbFrontend;
00596 }
00597 
00598 cEcmInfo::cEcmInfo(const char *Name, int Pid, int CaId, int ProvId)
00599 {
00600   Setup(); SetName(Name);
00601   ecm_pid=Pid;
00602   caId=CaId;
00603   provId=ProvId;
00604 }
00605 
00606 cEcmInfo::~cEcmInfo()
00607 {
00608   ClearCaDescr();
00609   free(name);
00610   delete rewriter;
00611 }
00612 
00613 void cEcmInfo::Setup(void)
00614 {
00615   cached=failed=false;
00616   name=0; caDescr=0; caDescrLen=0; dataIdx=-1;
00617   prgId=grPrgId=source=transponder=-1;
00618   ecm_table=0x80; emmCaId=0;
00619   rewriter=0; rewriterId=0;
00620   dvbAdapter=dvbFrontend=-1;
00621 }
00622 
00623 bool cEcmInfo::Compare(const cEcmInfo *e)
00624 {
00625   return grPrgId==e->grPrgId && source==e->source && transponder==e->transponder &&
00626          caId==e->caId && ecm_pid==e->ecm_pid && provId==e->provId;
00627 }
00628 
00629 void cEcmInfo::SetDvb(int DvbAdapter, int DvbFrontend)
00630 {
00631   dvbAdapter=DvbAdapter; dvbFrontend=DvbFrontend;
00632 }
00633 
00634 void cEcmInfo::SetSource(int GrPrgId, int Source, int Transponder)
00635 {
00636   grPrgId=GrPrgId; prgId=grPrgId%SIDGRP_SHIFT;
00637   source=Source;
00638   transponder=Transponder;
00639 }
00640 
00641 void cEcmInfo::ClearCaDescr(void)
00642 {
00643   free(caDescr); caDescr=0; caDescrLen=0;
00644 }
00645 
00646 bool cEcmInfo::AddCaDescr(const cEcmInfo *e)
00647 {
00648   bool res=AddCaDescr(e->caDescr,e->caDescrLen);
00649   if(e->dataIdx>=0 && (dataIdx<0 || e->dataIdx!=dataIdx)) res=true;
00650   dataIdx=e->dataIdx;
00651   return res;
00652 }
00653 
00654 void cEcmInfo::SetRewriter(void)
00655 {
00656   if(rewriterId>0) {
00657     if(!rewriter || rewriter->Id()!=rewriterId) {
00658       delete rewriter;
00659       rewriter=cRewriters::CreateById(rewriterId);
00660       }
00661     }
00662   else {
00663     delete rewriter;
00664     rewriter=0;
00665     }
00666 }
00667 
00668 bool cEcmInfo::AddCaDescr(const unsigned char *descr, int len)
00669 {
00670   bool res=false;
00671   if(descr && (!caDescr || caDescrLen!=len || memcmp(caDescr,descr,len)!=0)) {
00672     unsigned char *mem=MALLOC(unsigned char,len);
00673     if(mem) {
00674       ClearCaDescr();
00675       memcpy(mem,descr,len);
00676       caDescr=mem; caDescrLen=len;
00677       res=true;
00678       }
00679     else PRINTF(L_GEN_ERROR,"malloc failed in cEcmInfo::AddCaDescr()");
00680     }
00681   return res;
00682 }
00683 
00684 const unsigned char *cEcmInfo::GetCaDescr(int *l) const
00685 {
00686   if(l) *l=caDescrLen;
00687   return caDescr;
00688 }
00689 
00690 void cEcmInfo::SetDataIdx(int idx)
00691 {
00692   dataIdx=idx;
00693 }
00694 
00695 const unsigned char *cEcmInfo::Data(void) const
00696 {
00697   return (dataIdx>=0 && caDescr && caDescrLen>dataIdx) ? &caDescr[dataIdx] : 0;
00698 }
00699 
00700 void cEcmInfo::SetName(const char *Name)
00701 {
00702   free(name);
00703   name=strdup(Name);
00704 }
00705 
00706 // -- cPlainKey ----------------------------------------------------------------
00707 
00708 cPlainKey::cPlainKey(bool CanSupersede)
00709 {
00710   super=CanSupersede;
00711 }
00712 
00713 bool cPlainKey::Set(int Type, int Id, int Keynr, void *Key, int Keylen)
00714 {
00715   type=Type; id=Id; keynr=Keynr;
00716   return SetKey(Key,Keylen);
00717 }
00718 
00719 cString cPlainKey::PrintKeyNr(void)
00720 {
00721   return cString::sprintf("%02X",keynr);
00722 }
00723 
00724 int cPlainKey::IdSize(void)
00725 {
00726   return id>0xFF ? (id>0xFFFF ? 6 : 4) : 2;
00727 }
00728 
00729 cString cPlainKey::ToString(bool hide)
00730 {
00731   return cString::sprintf(hide ? "%c %.*X %s %.4s..." : "%c %.*X %s %s",type,IdSize(),id,*PrintKeyNr(),*Print());
00732 }
00733 
00734 // -- cMutableKey --------------------------------------------------------------
00735 
00736 cMutableKey::cMutableKey(bool Super)
00737 :cPlainKey(Super)
00738 {
00739   real=0;
00740 }
00741 
00742 cMutableKey::~cMutableKey()
00743 {
00744   delete real;
00745 }
00746 
00747 bool cMutableKey::SetKey(void *Key, int Keylen)
00748 {
00749   delete real;
00750   return (real=Alloc()) && real->SetKey(Key,Keylen);
00751 }
00752 
00753 bool cMutableKey::SetBinKey(unsigned char *Mem, int Keylen)
00754 {
00755   delete real;
00756   return (real=Alloc()) && real->SetBinKey(Mem,Keylen);
00757 }
00758 
00759 int cMutableKey::Size(void)
00760 {
00761   return real->Size();
00762 }
00763 
00764 bool cMutableKey::Cmp(cPlainKey *k)
00765 {
00766   cMutableKey *mk=dynamic_cast<cMutableKey *>(k); // high magic ;)
00767   return real->Cmp(mk ? mk->real : k);
00768 }
00769 
00770 void cMutableKey::Get(void *mem)
00771 {
00772   real->Get(mem);
00773 }
00774 
00775 cString cMutableKey::Print(void)
00776 {
00777   return real->Print();
00778 }
00779 
00780 // ----------------------------------------------------------------
00781 
00782 class cPlainKeyDummy : public cPlainKey {
00783 private:
00784   char *str;
00785   int len;
00786 protected:
00787   virtual cString Print(void);
00788   virtual cString PrintKeyNr(void) { return ""; }
00789 public:
00790   cPlainKeyDummy(void);
00791   ~cPlainKeyDummy();
00792   virtual bool Parse(const char *line);
00793   virtual bool Cmp(cPlainKey *k) { return false; }
00794   virtual void Get(void *mem) {}
00795   virtual int Size(void) { return len; }
00796   virtual bool SetKey(void *Key, int Keylen);
00797   virtual bool SetBinKey(unsigned char *Mem, int Keylen);
00798   };
00799 
00800 cPlainKeyDummy::cPlainKeyDummy(void):
00801 cPlainKey(false)
00802 {
00803   str=0;
00804 }
00805 
00806 cPlainKeyDummy::~cPlainKeyDummy()
00807 {
00808   free(str);
00809 }
00810 
00811 bool cPlainKeyDummy::SetKey(void *Key, int Keylen)
00812 {
00813   len=Keylen;
00814   free(str);
00815   str=MALLOC(char,len+1);
00816   if(str) strn0cpy(str,(char *)Key,len+1);
00817   return str!=0;
00818 }
00819 
00820 bool cPlainKeyDummy::SetBinKey(unsigned char *Mem, int Keylen)
00821 {
00822   return SetKey(Mem,Keylen);
00823 }
00824 
00825 cString cPlainKeyDummy::Print(void)
00826 {
00827   return str;
00828 }
00829 
00830 bool cPlainKeyDummy::Parse(const char *line)
00831 {
00832   unsigned char sid[3];
00833   int len;
00834   if(GetChar(line,&type,1) && (len=GetHex(line,sid,3,false))) {
00835     type=toupper(type); id=Bin2Int(sid,len);
00836     char *l=strdup(line);
00837     line=skipspace(stripspace(l));
00838     SetKey((void *)line,strlen(line));
00839     free(l);
00840     return true;
00841     }
00842   return false;
00843 }
00844 
00845 // -- cPlainKeyTypeDummy -------------------------------------------------------
00846 
00847 class cPlainKeyTypeDummy : public cPlainKeyType {
00848 public:
00849   cPlainKeyTypeDummy(int Type):cPlainKeyType(Type,false) {}
00850   virtual cPlainKey *Create(void) { return new cPlainKeyDummy; }
00851   };
00852 
00853 // -- cPlainKeyType ------------------------------------------------------------
00854 
00855 cPlainKeyType::cPlainKeyType(int Type, bool Super)
00856 {
00857   type=Type;
00858   cPlainKeys::Register(this,Super);
00859 }
00860 
00861 // -- cLastKey -----------------------------------------------------------------
00862 
00863 cLastKey::cLastKey(void)
00864 {
00865   lastType=lastId=lastKeynr=-1;
00866 }
00867 
00868 bool cLastKey::NotLast(int Type, int Id, int Keynr)
00869 {
00870   if(lastType!=Type || lastId!=Id || lastKeynr!=Keynr) {
00871     lastType=Type; lastId=Id; lastKeynr=Keynr;
00872     return true;
00873     }
00874   return false;
00875 }
00876 
00877 // -- cPlainKeys ---------------------------------------------------------------
00878 
00879 const char *externalAU=0;
00880 
00881 cPlainKeys keys;
00882 
00883 cPlainKeyType *cPlainKeys::first=0;
00884 
00885 cPlainKeys::cPlainKeys(void)
00886 :cStructList<cPlainKey>("keys",KEY_FILE,SL_READWRITE|SL_MISSINGOK|SL_WATCH|SL_VERBOSE)
00887 {}
00888 
00889 void cPlainKeys::Register(cPlainKeyType *pkt, bool Super)
00890 {
00891   PRINTF(L_CORE_DYN,"registering key type %c%s",pkt->type,Super?" (super)":"");
00892   pkt->next=first;
00893   first=pkt;
00894 }
00895 
00896 void cPlainKeys::Trigger(int Type, int Id, int Keynr)
00897 {
00898   if(lastkey.NotLast(Type,Id,Keynr))
00899     PRINTF(L_CORE_AUEXTERN,"triggered from findkey (%s)",*KeyString(Type,Id,Keynr));
00900   ExternalUpdate();
00901 }
00902 
00903 cPlainKey *cPlainKeys::FindKey(int Type, int Id, int Keynr, int Size, cPlainKey *key)
00904 {
00905   key=FindKeyNoTrig(Type,Id,Keynr,Size,key);
00906   if(!key) Trigger(Type,Id,Keynr);
00907   return key;
00908 }
00909 
00910 cPlainKey *cPlainKeys::FindKeyNoTrig(int Type, int Id, int Keynr, int Size, cPlainKey *key)
00911 {
00912   ListLock(false);
00913   for(key=key?Next(key):First(); key; key=Next(key))
00914     if(key->type==Type && key->id==Id && key->keynr==Keynr && (Size<0 || key->Size()==Size))
00915       break;
00916   ListUnlock();
00917   return key;
00918 }
00919 
00920 cPlainKey *cPlainKeys::NewFromType(int type)
00921 {
00922   cPlainKeyType *pkt;
00923   for(pkt=first; pkt; pkt=pkt->next)
00924     if(pkt->type==type) return pkt->Create();
00925   PRINTF(L_CORE_LOAD,"unknown key type '%c', adding dummy",type);
00926   pkt=new cPlainKeyTypeDummy(type);
00927   return pkt->Create();
00928 }
00929 
00930 bool cPlainKeys::AddNewKey(cPlainKey *nk, const char *reason)
00931 {
00932   cPlainKey *k;
00933   for(k=0; (k=FindKeyNoTrig(nk->type,nk->id,nk->keynr,-1,k)); )
00934     if(k->CmpExtId(nk) && k->Cmp(nk)) return false;
00935 
00936   cPlainKey *ref=0;
00937   cString ks=nk->ToString(true);
00938   PRINTF(L_GEN_INFO,"key update for ID %s",*ks);
00939   ums.Queue("%s %s",tr("Key update"),*ks);
00940   for(k=0; (k=FindKeyNoTrig(nk->type,nk->id,nk->keynr,nk->Size(),k)); ) {
00941     if(!k->CmpExtId(nk)) continue;
00942     if(nk->CanSupersede()) {
00943       PRINTF(L_GEN_INFO,"supersedes key: %s",*k->ToString(true));
00944       DelItem(k,ScSetup.SuperKeys==0);
00945       }
00946     if(!ref) ref=k;
00947     }
00948   char stamp[32], com[256];
00949   time_t tt=time(0);
00950   struct tm tm_r;
00951   strftime(stamp,sizeof(stamp),"%d.%m.%Y %T",localtime_r(&tt,&tm_r));
00952   snprintf(com,sizeof(com)," ; %s %s",reason,stamp);
00953   AddItem(nk,com,ref);
00954   return true;
00955 }
00956 
00957 bool cPlainKeys::NewKey(int Type, int Id, int Keynr, void *Key, int Keylen)
00958 {
00959   cPlainKey *nk=NewFromType(Type);
00960   if(nk) {
00961     nk->Set(Type,Id,Keynr,Key,Keylen);
00962     return AddNewKey(nk,"from AU");
00963     }
00964   return false;
00965 }
00966 
00967 bool cPlainKeys::NewKeyParse(char *line, const char *reason)
00968 {
00969   cPlainKey *nk=ParseLine(line);
00970   return nk && AddNewKey(nk,reason);
00971 }
00972 
00973 cPlainKey *cPlainKeys::ParseLine(char *line)
00974 {
00975   char *s=skipspace(line);
00976   cPlainKey *k=NewFromType(toupper(*s));
00977   if(k && !k->Parse(line)) { delete k; k=0; }
00978   return k;
00979 }
00980 
00981 cString cPlainKeys::KeyString(int Type, int Id, int Keynr)
00982 {
00983   cPlainKey *pk=NewFromType(Type);
00984   char *s;
00985   if(pk) {
00986     pk->type=Type; pk->id=Id; pk->keynr=Keynr;
00987     s=bprintf("%c %.*X %s",Type,pk->IdSize(),Id,*pk->PrintKeyNr());
00988     delete pk;
00989     }
00990   else s=strdup("unknown");
00991   return cString(s,true);
00992 }
00993 
00994 void cPlainKeys::PostLoad(void)
00995 {
00996   ListLock(false);
00997   if(Count() && LOG(L_CORE_KEYS)) {
00998     for(cPlainKey *dat=First(); dat; dat=Next(dat))
00999       PRINTF(L_CORE_KEYS,"keys %s",*dat->ToString(false));
01000     }
01001   ListUnlock();
01002 }
01003 
01004 void cPlainKeys::HouseKeeping(void)
01005 {
01006   if(trigger.TimedOut()) {
01007     trigger.Set(EXT_AU_INT);
01008     if(externalAU) PRINTF(L_CORE_AUEXTERN,"triggered from housekeeping");
01009     ExternalUpdate();
01010     }
01011 }
01012 
01013 void cPlainKeys::ExternalUpdate(void)
01014 {
01015   if(externalAU && ScSetup.AutoUpdate>0) {
01016     if(last.TimedOut()) {
01017       Lock();
01018       if(!Active())
01019         Start();
01020       else PRINTF(L_CORE_AUEXTERN,"still running");
01021       Unlock();
01022       }
01023     else PRINTF(L_CORE_AUEXTERN,"denied, min. timeout not expired");
01024     }
01025 }
01026 
01027 void cPlainKeys::Action(void)
01028 {
01029   last.Set(EXT_AU_MIN);
01030   PRINTF(L_CORE_AUEXTERN,"starting...");
01031   cTimeMs start;
01032   cPipe pipe;
01033   if(pipe.Open(externalAU,"r")) {
01034     char buff[1024];
01035     while(fgets(buff,sizeof(buff),pipe)) {
01036       char *line=skipspace(stripspace(buff));
01037       if(line[0]==0 || line[0]==';' || line[0]=='#') continue;
01038       NewKeyParse(line,"from ExtAU");
01039       }
01040     }
01041   pipe.Close();
01042   PRINTF(L_CORE_AUEXTERN,"done (elapsed %d)",(int)start.Elapsed());
01043 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines