|
SASC-NG
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 <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 }