add seekTitle to iSeekableService interface
[enigma2.git] / lib / service / servicefs.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
4 #include <errno.h>
5 #include <lib/service/servicefs.h>
6 #include <lib/service/service.h>
7 #include <lib/service/servicedvb.h>
8 #include <lib/base/init_num.h>
9 #include <lib/base/init.h>
10 #include <dirent.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14
15 class eStaticServiceFSInformation: public iStaticServiceInformation
16 {
17         DECLARE_REF(eStaticServiceFSInformation);
18 public:
19         RESULT getName(const eServiceReference &ref, std::string &name);
20         int getLength(const eServiceReference &ref) { return -1; }
21 };
22
23 DEFINE_REF(eStaticServiceFSInformation);
24
25 RESULT eStaticServiceFSInformation::getName(const eServiceReference &ref, std::string &name)
26 {
27         name = ref.path;
28         return 0;
29 }
30
31 // eServiceFactoryFS
32
33 eServiceFactoryFS::eServiceFactoryFS()
34 {
35         ePtr<eServiceCenter> sc;
36         
37         eServiceCenter::getPrivInstance(sc);
38         if (sc)
39         {
40                 std::list<std::string> extensions;
41                 sc->addServiceFactory(eServiceFactoryFS::id, this, extensions);
42         }
43         
44         m_service_information = new eStaticServiceFSInformation();
45 }
46
47 eServiceFactoryFS::~eServiceFactoryFS()
48 {
49         ePtr<eServiceCenter> sc;
50         
51         eServiceCenter::getPrivInstance(sc);
52         if (sc)
53                 sc->removeServiceFactory(eServiceFactoryFS::id);
54 }
55
56 DEFINE_REF(eServiceFactoryFS)
57
58         // iServiceHandler
59 RESULT eServiceFactoryFS::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
60 {
61         ptr=0;
62         return -1;
63 }
64
65 RESULT eServiceFactoryFS::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
66 {
67         ptr=0;
68         return -1;
69 }
70
71 RESULT eServiceFactoryFS::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
72 {
73         ptr = new eServiceFS(ref.path.c_str(), ref.getName().length() ? ref.getName().c_str() : 0);
74         return 0;
75 }
76
77 RESULT eServiceFactoryFS::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
78 {
79         ptr = m_service_information;
80         return 0;
81 }
82
83 RESULT eServiceFactoryFS::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
84 {
85         ptr = 0;
86         return -1;
87 }
88
89 // eServiceFS
90
91 DEFINE_REF(eServiceFS);
92
93 eServiceFS::eServiceFS(const char *path, const char *additional_extensions): path(path)
94 {
95         m_list_valid = 0;
96         if (additional_extensions)
97         {
98                 size_t slen=strlen(additional_extensions);
99                 char buf[slen+1];
100                 char *tmp=0, *cmds = buf;
101                 memcpy(buf, additional_extensions, slen+1);
102
103                 // strip spaces at beginning
104                 while(cmds[0] == ' ')
105                 {
106                         ++cmds;
107                         --slen;
108                 }
109
110                 // strip spaces at the end
111                 while(slen && cmds[slen-1] == ' ')
112                 {
113                         cmds[slen-1] = 0;
114                         --slen;
115                 }
116
117                 if (slen)
118                 {
119                         if (*cmds)
120                         {
121                                 int id;
122                                 char buf2[16];
123                                 while(1)
124                                 {
125                                         tmp = strchr(cmds, ' ');
126                                         if (tmp)
127                                                 *tmp = 0;
128                                         if (strstr(cmds, "0x"))
129                                         {
130                                                 if (sscanf(cmds, "0x%x:%s", &id, buf2) == 2)
131                                                         m_additional_extensions[id].push_back(buf2);
132                                                 else
133                                                         eDebug("parse additional_extension (%s) failed", cmds);
134                                         }
135                                         else
136                                         {
137                                                 if (sscanf(cmds, "%d:%s", &id, buf2) == 2)
138                                                         m_additional_extensions[id].push_back(buf2);
139                                                 else
140                                                         eDebug("parse additional_extension (%s) failed", cmds);
141                                         }
142                                         if (!tmp)
143                                                 break;
144                                         cmds = tmp+1;
145                                         while (*cmds && *cmds == ' ')
146                                                 ++cmds;
147                                 }
148                         }
149                 }
150         }
151 }
152
153 eServiceFS::~eServiceFS()
154 {
155 }
156
157 int lower(char c)
158 {
159         return std::tolower(static_cast<unsigned char>(c));
160 }
161
162 RESULT eServiceFS::getContent(std::list<eServiceReference> &list, bool sorted)
163 {
164         DIR *d=opendir(path.c_str());
165         if (!d)
166                 return -errno;
167         while (dirent *e=readdir(d))
168         {
169                 if (!(strcmp(e->d_name, ".") && strcmp(e->d_name, "..")))
170                         continue;
171                 
172                 std::string filename;
173                 
174                 filename = path;
175                 filename += e->d_name;
176                 
177                 struct stat s;
178                 if (::stat(filename.c_str(), &s) < 0)
179                         continue;
180                 
181                 if (S_ISDIR(s.st_mode))
182                         filename += "/";
183                 
184                 if (S_ISDIR(s.st_mode))
185                 {
186                         eServiceReference service(eServiceFactoryFS::id, 
187                                 eServiceReference::isDirectory|
188                                 eServiceReference::canDescent|eServiceReference::mustDescent|
189                                 eServiceReference::shouldSort|eServiceReference::sort1,
190                                 filename);
191                         service.data[0] = 1;
192                         list.push_back(service);
193                 } else
194                 {
195                         size_t e = filename.rfind('.');
196                         if (e != std::string::npos && e+1 < filename.length())
197                         {
198                                 std::string extension = filename.substr(e+1);
199                                 std::transform(extension.begin(), extension.end(), extension.begin(), lower);
200                                 int type = getServiceTypeForExtension(extension);
201
202                                 if (type == -1)
203                                 {
204                                         ePtr<eServiceCenter> sc;
205                                         eServiceCenter::getPrivInstance(sc);
206                                         type = sc->getServiceTypeForExtension(extension);
207                                 }
208                         
209                                 if (type != -1)
210                                 {
211                                         eServiceReference service(type,
212                                                 0,
213                                                 filename);
214                                         service.data[0] = 0;
215                                         list.push_back(service);
216                                 }
217                                 else
218                                         eDebug("unhandled extension %s", extension.c_str());
219                         }
220                 }
221         }
222         closedir(d);
223
224         if (sorted)
225                 list.sort(iListableServiceCompare(this));
226
227         return 0;
228 }
229
230 //   The first argument of this function is a format string to specify the order and
231 //   the content of the returned list
232 //   useable format options are
233 //   R = Service Reference (as swig object .. this is very slow)
234 //   S = Service Reference (as python string object .. same as ref.toString())
235 //   C = Service Reference (as python string object .. same as ref.toCompareString())
236 //   N = Service Name (as python string object)
237 //   when exactly one return value per service is selected in the format string,
238 //   then each value is directly a list entry
239 //   when more than one value is returned per service, then the list is a list of
240 //   python tuples
241 //   unknown format string chars are returned as python None values !
242 PyObject *eServiceFS::getContent(const char* format, bool sorted)
243 {
244         ePyObject ret;
245         std::list<eServiceReference> tmplist;
246         int retcount=1;
247
248         if (!format || !(retcount=strlen(format)))
249                 format = "R"; // just return service reference swig object ...
250
251         if (!getContent(tmplist, sorted))
252         {
253                 int services=tmplist.size();
254                 ePtr<iStaticServiceInformation> sptr;
255                 eServiceCenterPtr service_center;
256
257                 if (strchr(format, 'N'))
258                         eServiceCenter::getPrivInstance(service_center);
259
260                 ret = PyList_New(services);
261                 std::list<eServiceReference>::iterator it(tmplist.begin());
262
263                 for (int cnt=0; cnt < services; ++cnt)
264                 {
265                         eServiceReference &ref=*it++;
266                         ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
267                         for (int i=0; i < retcount; ++i)
268                         {
269                                 ePyObject tmp;
270                                 switch(format[i])
271                                 {
272                                 case 'R':  // service reference (swig)object
273                                         tmp = NEW_eServiceReference(ref);
274                                         break;
275                                 case 'C':  // service reference compare string
276                                         tmp = PyString_FromString(ref.toCompareString().c_str());
277                                         break;
278                                 case 'S':  // service reference string
279                                         tmp = PyString_FromString(ref.toString().c_str());
280                                         break;
281                                 case 'N':  // service name
282                                         if (service_center)
283                                         {
284                                                 service_center->info(ref, sptr);
285                                                 if (sptr)
286                                                 {
287                                                         std::string name;
288                                                         sptr->getName(ref, name);
289                                                         if (name.length())
290                                                                 tmp = PyString_FromString(name.c_str());
291                                                 }
292                                         }
293                                         if (!tmp)
294                                                 tmp = PyString_FromString("<n/a>");
295                                         break;
296                                 default:
297                                         if (tuple)
298                                         {
299                                                 tmp = Py_None;
300                                                 Py_INCREF(Py_None);
301                                         }
302                                         break;
303                                 }
304                                 if (tmp)
305                                 {
306                                         if (tuple)
307                                                 PyTuple_SET_ITEM(tuple, i, tmp);
308                                         else
309                                                 PyList_SET_ITEM(ret, cnt, tmp);
310                                 }
311                         }
312                         if (tuple)
313                                 PyList_SET_ITEM(ret, cnt, tuple);
314                 }
315         }
316         return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
317 }
318
319 RESULT eServiceFS::getNext(eServiceReference &ptr)
320 {
321         if (!m_list_valid)
322         {
323                 m_list_valid = 1;
324                 int res = getContent(m_list);
325                 if (res)
326                         return res;
327         }
328         
329         if (!m_list.size())
330         {
331                 ptr = eServiceReference();
332                 return -ERANGE;
333         }
334         
335         ptr = m_list.front();
336         m_list.pop_front();
337         return 0;
338 }
339
340 int eServiceFS::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
341 {
342                 /* directories first */
343         if ((a.flags & ~b.flags) & eServiceReference::isDirectory)
344                 return 1;
345         else if ((~a.flags & b.flags) & eServiceReference::isDirectory)
346                 return 0;
347                 /* sort by filename */
348         else
349                 return a.path < b.path;
350 }
351
352 RESULT eServiceFS::startEdit(ePtr<iMutableServiceList> &res)
353 {
354         res = 0;
355         return -1;
356 }
357
358 int eServiceFS::getServiceTypeForExtension(const char *str)
359 {
360         for (std::map<int, std::list<std::string> >::iterator sit(m_additional_extensions.begin()); sit != m_additional_extensions.end(); ++sit)
361         {
362                 for (std::list<std::string>::iterator eit(sit->second.begin()); eit != sit->second.end(); ++eit)
363                 {
364                         if (*eit == str)
365                                 return sit->first;
366                 }
367         }
368         return -1;
369 }
370
371 int eServiceFS::getServiceTypeForExtension(const std::string &str)
372 {
373         return getServiceTypeForExtension(str.c_str());
374 }
375
376 eAutoInitPtr<eServiceFactoryFS> init_eServiceFactoryFS(eAutoInitNumbers::service+1, "eServiceFactoryFS");