00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #if defined(_WIN32) && defined(_MSC_VER)
00025 # include <vos/corelibs/vosconfig-vc7.h>
00026 #else
00027 # include <vos/corelibs/vosconfig.h>
00028 #endif
00029
00030 #include <iostream>
00031 #include <fstream>
00032 #include <errno.h>
00033 #include <sys/types.h>
00034 #include <stdarg.h>
00035
00036 #ifdef HAVE_SYS_WAIT_H
00037 #include <sys/wait.h>
00038 #endif
00039
00040 #ifdef HAVE_UNISTD_H
00041 #include <unistd.h>
00042 #endif
00043
00044 #ifdef WIN32
00045 #include <windows.h>
00046 #include <process.h>
00047 #endif
00048
00049 #include <string.h>
00050 #include <stdio.h>
00051
00052 #include "typehelper.hh"
00053
00054 #ifdef HAVE_GNOME_VFS
00055 #include <libgnomevfs/gnome-vfs-application-registry.h>
00056 #endif
00057
00058 multimap<string, TypeHelper> helpers;
00059 multimap<int, ProcessEndCallback*> callbacks;
00060 set<int> processes;
00061
00062 void TypeHelper::addHelper(const string& line)
00063 {
00064 string objtype;
00065 string command;
00066 TypeHelper th;
00067
00068
00069 if(line == "" || line[0] == '#')
00070 return;
00071
00072
00073 string::size_type sep = line.find('=');
00074 if(sep == line.npos) {
00075
00076 return;
00077 }
00078
00079 objtype = line.substr(0, sep);
00080 command = line.substr(sep+1);
00081
00082
00083 if(command == "") return;
00084
00085
00086 string::size_type sp;
00087 while( (sp = objtype.find(" ")) != objtype.npos) objtype.erase(sp, 1);
00088 while( (sp = objtype.find("\t")) != objtype.npos) objtype.erase(sp, 1);
00089
00090
00091 string::size_type nsp = command.find_first_not_of(" \t");
00092 if(nsp != command.npos) {
00093 command.erase(0, nsp);
00094 }
00095
00096
00097 string::size_type c = objtype.find_first_of('(');
00098 if(c != string::npos) th.type = objtype.substr(c, objtype.size() - c - 1);
00099
00100
00101 th.setCommand(command);
00102
00103
00104 helpers.insert(pair<string, TypeHelper>(objtype, th));
00105 }
00106
00107 void TypeHelper::init(string filename)
00108 {
00109 bool error = true;
00110 ifstream input;
00111 input.open(filename.c_str());
00112 if(input.is_open()) {
00113 error = false;
00114 }
00115 if(error) {
00116 cerr << "libtypehelper: Warning: could not find helper apps config file " << filename << endl;
00117 return;
00118 }
00119
00120
00121 char s[256];
00122 for(int lineno = 0; input.getline(s, sizeof(s)); lineno++) {
00123 addHelper(s);
00124 }
00125 }
00126
00127 deque<TypeHelper> TypeHelper::findDataHelpers(const string& datatype, const string& tempfile) {
00128 string type = "property(";
00129 type += datatype + ")";
00130 pair<multimap<string, TypeHelper>::iterator, multimap<string, TypeHelper>::iterator> i = helpers.equal_range(type);
00131 deque<TypeHelper> ret;
00132 for(; i.first != i.second; i.first++) {
00133 ret.push_back((*(i.first)).second);
00134 ret.back().runFunc = DATA;
00135 ret.back().target = tempfile;
00136 }
00137
00138 #ifdef HAVE_GNOME_VFS
00139 GList* gl = gnome_vfs_application_registry_get_applications(datatype.c_str());
00140 GList* gliter;
00141
00142 for(gliter = gl; gliter; gliter = gliter->next) {
00143 TypeHelper th;
00144 th.type = datatype;
00145 th.parameters.push_back((char*)gliter->data);
00146 th.parameters.push_back("%f");
00147 th.target = tempfile;
00148 th.runFunc = DATA;
00149 ret.push_back(th);
00150 }
00151 #endif
00152
00153
00154 return ret;
00155 }
00156
00157 deque<TypeHelper> TypeHelper::findVobjectHelpers(const set<string>& types, const string& path) {
00158 deque<TypeHelper> ret;
00159 for(set<string>::const_iterator t = types.begin(); t != types.end(); t++) {
00160 string type = "vobject(";
00161 type += *t + ")";
00162 pair<multimap<string, TypeHelper>::iterator, multimap<string, TypeHelper>::iterator> i = helpers.equal_range(type);
00163 for(; i.first != i.second; i.first++) {
00164 ret.push_back((*(i.first)).second);
00165 ret.back().runFunc = VOBJECT;
00166 ret.back().target = path;
00167 }
00168 }
00169 return ret;
00170 }
00171
00172 int TypeHelper::run()
00173
00174 {
00175 switch(runFunc) {
00176 case DATA:
00177 break;
00178 case VOBJECT:
00179 char* env = (char*)malloc(strlen("VOS_STARTING_OBJECT=") + target.size() + 1);
00180 strcpy(env, "VOS_STARTING_OBJECT=");
00181 strcat(env, target.c_str());
00182 putenv(env);
00183 break;
00184 }
00185 char** args = (char**)malloc(sizeof(char*) * (parameters.size() + 1));
00186 unsigned int i;
00187 for(i = 0; i < parameters.size(); i++) {
00188 unsigned int p = parameters[i].find("%f");
00189 if(p != string::npos) parameters[i].replace(p, 2, target);
00190
00191 p = parameters[i].find("%d");
00192 if(p != string::npos) {
00193 string data;
00194 if(FILE* fl = fopen(target.c_str(), "r")) {
00195 char buf[256];
00196 int r;
00197 while(!feof(fl) && (r = fread(buf, 1, sizeof(buf), fl))) data.append(buf, r);
00198 fclose(fl);
00199 parameters[i].replace(p, 2, data);
00200 }
00201 }
00202 args[i] = (char*)parameters[i].c_str();
00203 }
00204 args[i] = 0;
00205
00206 int childpid;
00207 #ifdef WIN32
00208 if((childpid = _spawnvp(_P_NOWAIT, args[0], args)) < 0)
00209 #else
00210 if ((childpid = fork()) < 0)
00211 #endif
00212 {
00213 fprintf(stderr, "libtypehelper: error creating child process!: %s\n", strerror(errno));
00214 free(args);
00215 return -1;
00216 }
00217 if (childpid > 0) {
00218 processes.insert(childpid);
00219 free(args);
00220 return childpid;
00221 }
00222 #ifndef WIN32
00223 else {
00224
00225 if (execvp(args[0], args)) {
00226 fprintf(stderr, "libtypehelper: error executing \"%s\": %s\n", getCommand().c_str(), strerror(errno));
00227 }
00228
00229 exit(-1);
00230 }
00231 #endif
00232 return -1;
00233 }
00234
00235 string TypeHelper::getCommand()
00236 {
00237 string ret;
00238 for(deque<string>::iterator i = parameters.begin(); i != parameters.end(); i++) {
00239 ret += *i;
00240 ret += " ";
00241 }
00242 return ret;
00243 }
00244
00245 void TypeHelper::setCommand(const string& command) {
00246
00247 parameters.clear();
00248 unsigned int s = 0, e = 0;
00249 do {
00250 while(e < command.size() && (command[e] == ' ' || command[e] == '\t')) e++;
00251 s = e;
00252 while(e < command.size() && (command[e] != ' ' && command[e] != '\t')) e++;
00253
00254 parameters.push_back(command.substr(s, e-s));
00255 s = e;
00256 } while(s < command.size());
00257 }
00258
00259
00260
00261 void TypeHelper::addProcessEndCallback(int pid, ProcessEndCallback* cb)
00262 {
00263 if(processes.count(pid)) {
00264 callbacks.insert(pair<int, ProcessEndCallback*>(pid, cb));
00265 }
00266 }
00267
00268 void TypeHelper::removeProcessEndCallback(int pid, ProcessEndCallback* call)
00269 {
00270 pair<multimap<int, ProcessEndCallback*>::iterator, multimap<int, ProcessEndCallback*>::iterator> cb
00271 = callbacks.equal_range(pid);
00272 while(cb.first != cb.second) {
00273 multimap<int, ProcessEndCallback*>::iterator d = cb.first;
00274 cb.first++;
00275 if((*d).second == call) callbacks.erase(d);
00276 }
00277 }
00278
00279 void TypeHelper::checkProcesses()
00280 {
00281 for(set<int>::iterator i = processes.begin(); i != processes.end(); ) {
00282 #ifdef WIN32
00283 HANDLE hd = OpenProcess(PROCESS_QUERY_INFORMATION, false, *i);
00284 DWORD retval;
00285 GetExitCodeProcess(hd, &retval);
00286 CloseHandle(hd);
00287 if(retval != STILL_ACTIVE)
00288 #else
00289 if(waitpid(*i, 0, WNOHANG) > 0)
00290 #endif
00291 {
00292 pair<multimap<int, ProcessEndCallback*>::iterator, multimap<int, ProcessEndCallback*>::iterator> cb
00293 = callbacks.equal_range(*i);
00294 while(cb.first != cb.second) {
00295 (*cb.first).second->notifyProcessTerminate(*i);
00296 multimap<int, ProcessEndCallback*>::iterator d = cb.first;
00297 cb.first++;
00298 callbacks.erase(d);
00299 }
00300
00301 set<int>::iterator n = i;
00302 i++;
00303 processes.erase(n);
00304 } else i++;
00305 }
00306 }
00307
00308 DeleteTempFile::DeleteTempFile(const string& f) : file(f), other_pids(0)
00309 { }
00310
00311 DeleteTempFile::DeleteTempFile(const string& f, set<int>* pidset) : file(f), other_pids(pidset)
00312 { }
00313
00314 DeleteTempFile::~DeleteTempFile()
00315 { }
00316
00317 void DeleteTempFile::notifyProcessTerminate(int pid)
00318 {
00319 if(other_pids) {
00320 other_pids->erase(pid);
00321 if(other_pids->empty()) {
00322 unlink(file.c_str());
00323 delete other_pids;
00324 }
00325 delete this;
00326 } else {
00327 unlink(file.c_str());
00328 delete this;
00329 }
00330 }
00331
00332