/* * MP3/MPlayer plugin to VDR (C++) * * (C) 2001-2005 Stefan Huelswitt * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "data.h" // ---------------------------------------------------------------- const char *mountscript = "mount.sh"; char *Quote(const char *str) { char *nstr=MALLOC(char,strlen(str)*2); char *p=nstr; while(*str) { switch(*str) { case '$': // dollar case '\\': // backslash case '\"': // double quote case '`': // back tick *p++='\\'; break; } *p++=*str++; } *p=0; return nstr; } char *AddPath(const char *dir, const char *filename) { char *name=0; asprintf(&name,"%s/%s",dir,filename); return name; } bool CheckVDRVersion(int Version, int Major, int Minor, const char *text) { static char vv[] = VDRVERSION; int version, major, minor; if(sscanf(vv,"%d.%d.%d",&version,&major,&minor)==3) { if(versionBaseDir(),subdir); DIR *d=opendir(dir); if(d) { struct dirent64 *e; while((e=readdir64(d))) { if(!strcmp(e->d_name,".") || !strcmp(e->d_name,"..")) continue; free(f); if(!(f=AddPath(dir,e->d_name))) continue; struct stat64 st; if(stat64(f,&st)<0) { esyslog("music: ERROR: stat(1) %s: %s",f,strerror(errno)); continue; } if(S_ISLNK(st.st_mode)) { char *of=f; f=ReadLink(of); free(of); if(!f) continue; if(stat64(f,&st)<0) { esyslog("music: ERROR: stat(2) %s: %s",f,strerror(errno)); continue; } } if(S_ISDIR(st.st_mode)) { if(type==stFile && recursiv) { char *s=aprintf(subdir ? "%2$s/%1$s":"%s",e->d_name,subdir); ScanDir(src,s,type,spec,excl,recursiv); free(s); continue; } if(type!=stDir) continue; } if(S_ISREG(st.st_mode)) { if(type!=stFile) continue; if(spec) { bool ok=false; for(const char * const *m=spec; *m; m++) { int n=fnmatch(*m,e->d_name,FNM_CASEFOLD); if(n==0) { ok=true; break; } if(n!=FNM_NOMATCH) esyslog("music: ERROR: fnmatch(1) %s: %s",*m,strerror(errno)); } if(!ok) continue; } if(excl) { bool ok=true; for(const char * const *m=excl; *m; m++) { int n=fnmatch(*m,e->d_name,FNM_CASEFOLD); if(n==0) { ok=false; break; } if(n!=FNM_NOMATCH) esyslog("music: ERROR: fnmatch(2) %s: %s",*m,strerror(errno)); } if(!ok) continue; } } DoItem(src,subdir,e->d_name); } closedir(d); } else { esyslog("music: ERROR: opendir %s: %s",dir,strerror(errno)); res=false; } free(dir); free(f); return res; } // -- cFileObj -------------------------------------------------------------- cFileObj::cFileObj(cFileSource *Source, const char *Subdir, const char *Name, const eObjType Type) { path=fpath=0; source=Source; subdir=Subdir ? strdup(Subdir):0; name=Name ? strdup(Name):0; type=Type; Set(); } cFileObj::cFileObj(const cFileObj *obj) { path=fpath=0; source=obj->source; subdir=obj->subdir ? strdup(obj->subdir):0; name=obj->name ? strdup(obj->name):0; type=obj->type; Set(); } cFileObj::~cFileObj() { free(name); free(subdir); free(path); free(fpath); } #if APIVERSNUM >= 10315 int cFileObj::Compare(const cListObject &ListObject) const { cFileObj *obj=(cFileObj *)&ListObject; if(type==otParent) return obj->type==otParent ? 0:-1; if(obj->type==otParent) return 1; if(type==otBase) return obj->type==otBase ? 0:1; if(obj->type==otBase) return -1; if(type!=obj->type) { if(type==otFile) return 1; return -1; } return strcasecmp(path,obj->path); } #else bool cFileObj::operator<(const cListObject &ListObject) { cFileObj *obj=(cFileObj *)&ListObject; if(type==otParent) return obj->type==otParent ? false:true; if(obj->type==otParent) return false; if(type==otBase) return false; if(obj->type==otBase) return true; if(type!=obj->type) { if(type==otFile) return false; return true; } return strcasecmp(path,obj->path)<0; } #endif void cFileObj::SplitAndSet(const char *Path) { free(subdir); subdir=0; const char *p=Path; if(Path[0]=='/') { int l=strlen(source->BaseDir()); if(!strncasecmp(Path,source->BaseDir(),l)) p+=l+1; else { l=strlen(source->RealBaseDir()); if(!strncasecmp(Path,source->RealBaseDir(),l)) p+=l+1; else { char buff[strlen(Path)+5]; strcpy(buff,"/"); p++; while(1) { char real[PATH_MAX+1]; if(!realpath(buff,real)) { if(errno!=ENOENT && errno!=ENOTDIR) esyslog("music: ERROR: realpath: %s: %s",buff,strerror(errno)); p=Path+1; break; } if(!strncasecmp(real,source->RealBaseDir(),l)) break; const char *r=index(p,'/'); if(!r) { esyslog("music: ERROR: can't find source basedir in '%s'. Outside source?",Path); p=Path+1; break; } strn0cpy(buff,Path,r-Path+1); p=r+1; } } } } const char *s=rindex(p,'/'); if(s) { const int l=s-p+1; subdir=MALLOC(char,l); if(subdir) strn0cpy(subdir,p,l); SetName(s+1); } else SetName(p); } void cFileObj::SetName(const char *Name) { free(name); name=Name ? strdup(Name):0; Set(); } void cFileObj::Set(void) { free(path); path=0; asprintf(&path,subdir ? "%2$s/%1$s":"%s",name,subdir); free(fpath); fpath=0; MakeFullName(&fpath,name); } void cFileObj::MakeFullName(char **fp, const char *Name) { asprintf(fp,subdir ? "%1$s/%3$s/%2$s":"%s/%s",source->BaseDir(),Name,subdir); } bool cFileObj::GuessType(void) { struct stat64 ds; if(!stat64(fpath,&ds)) { if(S_ISREG(ds.st_mode)) type=otFile; else if(S_ISDIR(ds.st_mode)) type=subdir ? otDir:otBase; else return false; return true; } return false; } bool cFileObj::Exists(void) { if(type==otFile) { struct stat64 ds; if(!stat64(fpath,&ds) && S_ISREG(ds.st_mode) && !access(fpath,R_OK)) return true; } return false; } bool cFileObj::TestName(const char *newName) { bool r=false; if(type==otFile) { char *fname; MakeFullName(&fname,newName); if(access(fname,F_OK)==0) r=true; free(fname); } return r; } bool cFileObj::Rename(const char *newName) { bool r=false; if(type==otFile) { char *fname; MakeFullName(&fname,newName); if(access(fname,F_OK) && (!rename(fpath,fname))) { SetName(newName); r=true; } free(fname); } return r; } bool cFileObj::Create(const char *newName) { bool r=false; if(type==otFile) { char *fname; MakeFullName(&fname,newName); FILE *newf; if(access(fname,F_OK) && (newf=fopen(fname,"w"))) { fclose(newf); SetName(newName); r=true; } free(fname); } return r; } bool cFileObj::Delete(void) { if(type==otFile && !unlink(fpath)) return true; return false; } // -- cFileObjItem --------------------------------------------------------- cFileObjItem::cFileObjItem(const char *Path, const char *Name, const eObjType Type) { path=Path ? strdup(Path):0; name=Name ? strdup(Name):0; type=Type; // Set(); } cFileObjItem::cFileObjItem(const cFileObjItem *objfile) { path=objfile->path ? strdup(objfile->path):0; name=objfile->name ? strdup(objfile->name):0; type=objfile->type; // Set(); } cFileObjItem::~cFileObjItem() { free(name); free(path); } /* void cFileObjItem::Set(void) { free(path); path=0; asprintf(&path,subdir ? "%2$s/%1$s":"%s",name,subdir); free(fpath); fpath=0; MakeFullName(&fpath,name); } void cFileObj::MakeFullName(char **fp, const char *Name) { asprintf(fp,subdir ? "%1$s/%3$s/%2$s":"%s/%s",source->BaseDir(),Name,subdir); } void cFileObjItem::SetName(const char *Name) { free(name); name=Name ? strdup(Name):0; } void cFileObj::MakeFullName(char **fp, const char *Name) { asprintf(fp,subdir ? "%1$s/%3$s/%2$s":"%s/%s",source->BaseDir(),Name,subdir); } */ // -- cDirList -------------------------------------------------------------- bool cDirList::Load(cFileSource *src, const char *subdir, const char * const *excl) { static const char *excl_s[] = { ".*",0 }; bool res=false; Clear(); if(subdir) Add(new cFileObj(src,subdir,"..",otParent)); otype=otDir; if(ScanDir(src,subdir,stDir,0,0,false)) { otype=otFile; if(!excl) excl=excl_s; if(ScanDir(src,subdir,stFile,src->Include(),excl,false)) res=true; } Sort(); return res; } void cDirList::DoItem(cFileSource *src, const char *subdir, const char *name) { Add(new cFileObj(src,subdir,name,otype)); } // -- cFileSource -------------------------------------------------------------- cFileSource::cFileSource(void) { browsedir=browseparent=0; basedir=realbasedir=description=0; useCount=0; needsmount=false; include=0; incCount=0; } cFileSource::cFileSource(const char *Basedir, const char *Description, const bool NeedsMount, const char *Include) { browsedir=browseparent=0; basedir=realbasedir=description=0; useCount=0; include=0; incCount=0; Set(Basedir,Description,NeedsMount,Include); } cFileSource::~cFileSource() { ClearRemember(); Clear(); } void cFileSource::Clear(void) { free(basedir); basedir=0; free(realbasedir); realbasedir=0; free(description); description=0; for(int i=0; i0); } #ifdef DEBUG if(include) { printf("music: data: filesource %s includes (count=%d):",basedir,incCount); for(int i=0; i=3) { char *base2=skipspace(stripspace(base)); int l=strlen(base2); while(l>0 && base2[l-1]=='/') { esyslog("music: WARNING: removing trailing '/' from base %s",base2); base2[l-1]=0; l--; } Set(base2,skipspace(stripspace(des)),needsmount!=0,n>3?skipspace(stripspace(incl)):0); // do some checking of the basedir and issue a warning if apropriate if(access(realbasedir,R_OK)) { esyslog("music: WARNING: source base %s not found/permission denied",realbasedir); } else { struct stat64 ds; if(lstat64(realbasedir,&ds)) { esyslog("music: WARNING: can't stat source base %s",realbasedir); } else if(!S_ISDIR(ds.st_mode)) { esyslog("music: WARNING: source base %s is not a directory",realbasedir); } } return true; } return false; } bool cFileSource::Action(eAction act) { static const char *str[] = { "mount","unmount","eject","status" }; char *cmd=0; asprintf(&cmd,"%s %s %s",mountscript,str[act],basedir); bool res=(system(cmd)==0); free(cmd); return res; } bool cFileSource::Mount(void) { bool res=false; if(needsmount && (res=Action(acMount))) ClearRemember(); return res; } bool cFileSource::Unmount(void) { bool res=false; if(needsmount) { if(!useCount && (res=Action(acUnmount))) ClearRemember(); } return res; } bool cFileSource::Eject(void) { bool res=false; if(needsmount) { if(!useCount && (res=Action(acEject))) ClearRemember(); } return res; } bool cFileSource::Status(void) { if(needsmount) return Action(acStatus); return true; } // -- cFileSources -------------------------------------------------------------- bool cFileSources::Load(const char *filename, bool dummy) { if(cConfig::Load(filename,true)) { SetSource(First()); return true; } return false; } cFileSource *cFileSources::FindSource(const char *filename, bool external) { cFileSource *src=First(); if(external) { while(src) { if(startswith(filename,src->RealBaseDir())) return src; src=Next(src); } } else { while(src) { // printf("TEST TEST : filename = %s || RealBaseDir = %s\n", filename , src->RealBaseDir()); if(!strcmp(filename,src->RealBaseDir())) { // printf("FOUND ONE: %s and needsmount=%i\n",src->RealBaseDir(),src->NeedsMount()); return src; } src=Next(src); } } return 0; }