/* This file is part of vdr-filebrowser. vdr-filebrowser 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 3 of the License, or (at your option) any later version. vdr-filebrowser 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 Foobar. If not, see . */ #include #include #include #include #include #include #include #include "commands.h" #ifdef FILEBROWSER_PLUGIN_BUILD #include "menu-threads.h" #endif #include "statebag.h" cFilebrowserCommand::cFilebrowserCommand(cFilebrowserStatebag* Statebag) { Name= NULL; Pattern=NULL; Confirm=false; UseDestination=false; UseCurrentFile=false; UseSelectedFiles=false; UseNewDestination=false; UseUserInput=false; UseUserInputPassword=false; Synchronous=false; Menu=true; AccessCode=NULL; RemoveFinished=false; PatternIsShellscript=false; State=osContinue; this->Statebag=Statebag; } cFilebrowserCommand::~cFilebrowserCommand() { if(Name) free(Name); if(Pattern) free(Pattern); if(AccessCode) free(AccessCode); } bool cFilebrowserCommand::Matches(const char* Filename) { bool Match=true; if(Statebag && (Statebag->GetSelectedFiles()->Count() > 0)) { for(cStringContainer* i=Statebag->GetSelectedFiles()->First(); i; i=Statebag->GetSelectedFiles()->Next(i)) { Match&=MatchesSingleFile(i->GetObject()); if(!Match) { break; } } } else { Match=MatchesSingleFile(Filename); } return Match; } bool cFilebrowserCommand::MatchesSingleFile(const char* Filename) { if(!Filename) { return false; } if(PatternIsShellscript) { cCommandParser* Parser=new cCommandParser(Pattern); Parser->AddReplacement('f', Filename); cString Command=Parser->Parse(); D(fprintf(stderr, "Trying to execute %s\n", *Command)); int Status=SystemExec(*Command); D(fprintf(stderr, "Executed \"%s\": %d\n", *Command, Status)); return Status == 0; } else { if(Pattern[0]!='/') { char* filename_tmp=NULL; Filename=(Filename && (filename_tmp=(char*)strrchr(Filename, '/'))) ? filename_tmp + 1 : NULL; } if(Filename==NULL) { return false; } return fnmatch(Pattern, Filename, FNM_FILE_NAME | FNM_EXTMATCH) != FNM_NOMATCH; } } const char* cFilebrowserCommand::GetName() { return tr(Name); } const char* cFilebrowserCommand::GetLongName() { return tr(Name); } bool cFilebrowserCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { return true; } eKeys cFilebrowserCommand::GetHotkey() { return kNone; } #ifdef FILEBROWSER_PLUGIN_BUILD /* Implementation cConfigCommand */ cFilebrowserConfigCommand::cFilebrowserConfigCommand(cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { Command=NULL; }; char* cFilebrowserConfigCommand::FlagHandler(const char* OrgString, const char* CurrentPos, const cCommandParser::cHandlerParameters* Params) { *((bool*)Params->Data)=true; return NULL; } cFilebrowserConfigCommand* cFilebrowserConfigCommand::Parse(char* Config, cFilebrowserStatebag* Statebag) { cFilebrowserConfigCommand* Command=new cFilebrowserConfigCommand(Statebag); cConfigParser Parser=cConfigParser(Config); for(char* Text=Parser.First(); Text; Text=Parser.Next()) { switch(Parser.GetFieldNumber()) { case 0: //The name of this command if(Text[Parser.GetCurrentLength()-1]=='?') { Text[Parser.GetCurrentLength()-1]='\0'; Command->Confirm=true; D(fprintf(stderr, "I will ask ")); } D(fprintf(stderr, "[doing realloc] ")); Command->Name=(char*)realloc(Command->Name, Parser.GetCurrentLength() + 1); D(fprintf(stderr, "[copying %s] ", Text)); strcpy(Command->Name, Text); D(fprintf(stderr, "\"%s\" ", Command->Name)); break; case 1: //The pattern of this command Command->PatternIsShellscript=(Text[0]=='!'); Command->Pattern=(char*)realloc(Command->Pattern, Parser.GetCurrentLength() + 1); strcpy(Command->Pattern, Text + (Command->PatternIsShellscript ? 1 : 0)); D(fprintf(stderr, "\"%s\" ", Command->Pattern)); break; case 2: //The command string of this command Command->Command=(char*)realloc(Command->Command, Parser.GetCurrentLength() + 1); strcpy(Command->Command, Text); D(fprintf(stderr, "\"%s\" ", Command->Command)); break; case 3: //Flags for this command Command->Synchronous=strchr(Text, 's'); Command->Menu=!strchr(Text, 'b'); Command->RemoveFinished=strchr(Text, 'r'); D(fprintf(stderr, " Sync:%d Menu:%d Remove:%d ", Command->Synchronous, Command->Menu, Command->RemoveFinished)); break; case 4: //An access code Command->AccessCode=strdup(Text); D(fprintf(stderr, " Access code: %s ", Command->AccessCode)); break; } } D(fprintf(stderr, "\n")); if(!Command->Pattern || !Command->Command) { D(fprintf(stderr, "Misconfigured commands.conf - skipping this entry [was \"%s\"]!\n", Config)); esyslog("[filebrowser] Misconfigured commands.conf - skipping this entry [was \"%s\"]!\n", Config); return NULL; } //Set Use-Flags cCommandParser CommandParser(Command->Command, false, false); CommandParser.AddHandler('D', &cFilebrowserConfigCommand::FlagHandler, &Command->UseNewDestination); CommandParser.AddHandler('d', &cFilebrowserConfigCommand::FlagHandler, &Command->UseDestination); CommandParser.AddHandler('M', &cFilebrowserConfigCommand::FlagHandler, &Command->UseSelectedFiles); CommandParser.AddHandler('m', &cFilebrowserConfigCommand::FlagHandler, &Command->UseSelectedFiles); CommandParser.AddHandler('f', &cFilebrowserConfigCommand::FlagHandler, &Command->UseCurrentFile); CommandParser.AddHandler('i', &cFilebrowserConfigCommand::FlagHandler, &Command->UseUserInput); CommandParser.AddHandler('p', &cFilebrowserConfigCommand::FlagHandler, &Command->UseUserInputPassword); CommandParser.Parse(); D(fprintf(stderr, "NewDest %d, Dest %d, SelFiles %d, File %d, UserInput %d, UserInputPassword %d\n", Command->UseNewDestination, Command->UseDestination, Command->UseSelectedFiles, Command->UseCurrentFile, Command->UseUserInput, Command->UseUserInputPassword)); return Command; } cFilebrowserConfigCommand::~cFilebrowserConfigCommand() { if(Command) free(Command); } bool cFilebrowserConfigCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { D(fprintf(stderr, "got dest %s and %d marked files\n", DestinationFile, Statebag->GetSelectedFiles()->Count())); cConfigCommandThread* Thread=new cConfigCommandThread(Statebag, DestinationFile, CurrentFile, this); if(Synchronous) { //TODO: Move this to filebrowser.c, implement some kind of wait function to wait until the thread is finished pid_t child_pid=fork(); if(child_pid == 0) { int MaxPossibleFileDescriptors = getdtablesize(); for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++) close(i); Thread->Execute(); } else if(child_pid < 0) { LOG_ERROR; } else { int status; waitpid(child_pid, &status, 0); delete Thread; } } else { Statebag->GetThreads()->Add(new cThreadContainer(Thread)); } return true; } char* cFilebrowserConfigCommand::GetCommand() { return Command; } #endif /* Implementation cFilebrowserMarkCommand */ cFilebrowserMarkCommand::cFilebrowserMarkCommand(cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { Name=strcpyrealloc(Name, tr("Mark")); } bool cFilebrowserMarkCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { cOsdMenuFilebrowser* FbMenu=(cOsdMenuFilebrowser*)Menu; cOsdItemFileEntry* Entry=(cOsdItemFileEntry*)FbMenu->Get(FbMenu->Current()); Statebag->GetSelectedFiles()->Add(new cStringContainer(strdup(Entry->GetFilename()))); Entry->Mark(true); FbMenu->DisplayCurrent(true); FbMenu->UpdateHelp(); return true; } bool cFilebrowserMarkCommand::Matches(const char* Filename) { return Filename && !Statebag->GetSelectedFiles()->Contains(Filename) && strcmp(strlen(Filename) > 2 ? Filename + strlen(Filename) - 2 : "", "..") != 0; } /* Implementation cFilebrowserMarkAllCommand */ cFilebrowserMarkAllCommand::cFilebrowserMarkAllCommand(cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { Name=strcpyrealloc(Name, tr("Mark all")); } bool cFilebrowserMarkAllCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { cOsdMenuFilebrowser* FbMenu=(cOsdMenuFilebrowser*)Menu; for(cOsdItemFileEntry* Entry=(cOsdItemFileEntry*)FbMenu->First(); Entry; Entry=(cOsdItemFileEntry*)Entry->Next()) { if(!Entry->IsMarked() && !Entry->IsParentDirectory()) { Entry->Mark(true); Statebag->GetSelectedFiles()->Add(new cStringContainer(strdup(Entry->GetFilename()))); } } FbMenu->UpdateHelp(); FbMenu->Display(); return true; } bool cFilebrowserMarkAllCommand::Matches(const char* Filename) { return true; } /* Implementation cFilebrowserUnmarkCommand */ cFilebrowserUnmarkCommand::cFilebrowserUnmarkCommand(cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { Name=strcpyrealloc(Name, tr("Unmark")); } bool cFilebrowserUnmarkCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { cOsdMenuFilebrowser* FbMenu=(cOsdMenuFilebrowser*)Menu; cOsdItemFileEntry* Entry=(cOsdItemFileEntry*)FbMenu->Get(FbMenu->Current()); Statebag->GetSelectedFiles()->Remove(Entry->GetFilename()); Entry->Mark(false); FbMenu->DisplayCurrent(true); FbMenu->UpdateHelp(); return true; } bool cFilebrowserUnmarkCommand::Matches(const char* Filename) { return Filename && Statebag->GetSelectedFiles()->Contains(Filename) && strcmp(strlen(Filename) > 2 ? Filename + strlen(Filename) - 2 : "", "..") != 0; } /* Implementation cFilebrowserUnmarkAllCommand */ cFilebrowserUnmarkAllCommand::cFilebrowserUnmarkAllCommand(cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { Name=strcpyrealloc(Name, tr("Unm. all")); } bool cFilebrowserUnmarkAllCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { cOsdMenuFilebrowser* FbMenu=(cOsdMenuFilebrowser*)Menu; Statebag->GetSelectedFiles()->Clear(); for(cOsdItemFileEntry* Entry=(cOsdItemFileEntry*)FbMenu->First(); Entry; Entry=(cOsdItemFileEntry*)Entry->Next()) { Entry->Mark(false); } FbMenu->UpdateHelp(); FbMenu->Display(); return true; } bool cFilebrowserUnmarkAllCommand::Matches(const char* Filename) { return Statebag->GetSelectedFiles()->Count() > 0; } /* Implementation of cFilebrowserDestinationContainerCommand */ cFilebrowserDestinationContainerCommand::cFilebrowserDestinationContainerCommand(cFilebrowserCommand* Command, char* CurrentFile, cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { this->Command=Command; UseSelectedFiles=Command->UsesSelectedFiles(); UseNewDestination=Command->UsesNewDestination(); UseCurrentFile=Command->UsesCurrentFile(); UseUserInput=Command->UsesUserInput(); UseUserInputPassword=Command->UsesUserInputPassword(); Menu=Command->ShowMenu(); Synchronous=Command->IsSynchronous(); RemoveFinished=Command->RemoveWhenFinished(); Confirm=Command->NeedsConfirmation(); this->CurrentFile=strdup(CurrentFile); DestinationFile=NULL; Name=strcpyrealloc(Name, tr("OK")); } cFilebrowserDestinationContainerCommand::~cFilebrowserDestinationContainerCommand() { if(CurrentFile) free(CurrentFile); if(DestinationFile) free(DestinationFile); } bool cFilebrowserDestinationContainerCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { if(this->DestinationFile) free(this->DestinationFile); this->DestinationFile=strdup(CurrentFile); for(cOsdItem* i=Menu->First(); i!=NULL; i=Menu->cOsdMenu::Next(i)) { if(dynamic_cast(i)) { ((cOsdMenuFilebrowser*)Menu)->Del(i->Index()); } } return Command->Execute(Menu, this->DestinationFile, this->CurrentFile); } bool cFilebrowserDestinationContainerCommand::Matches(const char* Filename) { return Command ? Command->MatchesDestination(Filename) : false; } const char* cFilebrowserDestinationContainerCommand::GetAccessCode() { return Command ? Command->GetAccessCode() : NULL; } /* Implementation of cFilebrowserDestinationAbortCommand */ cFilebrowserDestinationAbortCommand::cFilebrowserDestinationAbortCommand(cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { Name=strcpyrealloc(Name, tr("Abort")); } bool cFilebrowserDestinationAbortCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { ((cOsdMenuFilebrowser*)Menu)->Task=taskBrowse; for(cOsdItem* i=Menu->First(); i!=NULL; i=Menu->cOsdMenu::Next(i)) { if(dynamic_cast(i)) { ((cOsdMenuFilebrowser*)Menu)->Del(i->Index()); } } ((cOsdMenuFilebrowser*)Menu)->Refresh(); return true; } bool cFilebrowserDestinationAbortCommand::Matches(const char* Filename) { return true; } /* Implementation of cFilebrowserDestinationNewCommand */ cFilebrowserDestinationNewCommand::cFilebrowserDestinationNewCommand(cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { Name=strcpyrealloc(Name, tr("New")); } bool cFilebrowserDestinationNewCommand::Execute(cOsdMenu* Menu, char* DestinationFile, char* CurrentFile) { char* val=(char*)malloc(255); sprintf(val, tr("New file")); cOsdItemNewFileEntry* NewItem=new cOsdItemNewFileEntry(val, *(Statebag->CurrentDirectory)); Menu->Add(NewItem, true); ((cOsdMenuFilebrowser*)Menu)->DisplayCurrent(true); NewItem->ProcessKey(kNone); Menu->Display(); return true; } bool cFilebrowserDestinationNewCommand::Matches(const char* Filename) { return true; } #ifdef FILEBROWSER_PLUGIN_BUILD /* Implementation of cFilebrowserCommandThreadList */ cFilebrowserCommandThreadList::cFilebrowserCommandThreadList(cFilebrowserStatebag* Statebag) : cFilebrowserCommand(Statebag) { Name=strcpyrealloc(Name, tr("Threads")); LongName=(char*)malloc(strlen(tr("Threads (%d of %d running)")) + 10); } cFilebrowserCommandThreadList::~cFilebrowserCommandThreadList() { free(LongName); } const char* cFilebrowserCommandThreadList::GetLongName() { int threadCount=0; int runningThreadCount=0; for(cThreadContainer* i=Statebag->GetThreads()->First(); i; i=Statebag->GetThreads()->Next(i)) { threadCount++; if(i->GetObject()->GetState()==tsRunning) { runningThreadCount++; } } if(threadCount) { sprintf(LongName, tr("Threads (%d of %d running)"), runningThreadCount, threadCount); } else { strcpy(LongName, Name); } return LongName; } bool cFilebrowserCommandThreadList::Execute(cOsdMenu* Menu, char* DestinationFile, char* SelectedFile) { cOsdMenuFilebrowser* FbMenu=(cOsdMenuFilebrowser*)Menu; FbMenu->AddSubMenu(new cOsdMenuThreadList(Statebag)); return true; } bool cFilebrowserCommandThreadList::Matches(const char* Filename) { return true; } #endif