renable callable func to selectable func
[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                 sc->addServiceFactory(eServiceFactoryFS::id, this);
40         
41         m_service_information = new eStaticServiceFSInformation();
42 }
43
44 eServiceFactoryFS::~eServiceFactoryFS()
45 {
46         ePtr<eServiceCenter> sc;
47         
48         eServiceCenter::getPrivInstance(sc);
49         if (sc)
50                 sc->removeServiceFactory(eServiceFactoryFS::id);
51 }
52
53 DEFINE_REF(eServiceFactoryFS)
54
55         // iServiceHandler
56 RESULT eServiceFactoryFS::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
57 {
58         ptr=0;
59         return -1;
60 }
61
62 RESULT eServiceFactoryFS::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
63 {
64         ptr=0;
65         return -1;
66 }
67
68 RESULT eServiceFactoryFS::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
69 {
70         ptr = new eServiceFS(ref.path.c_str());
71         return 0;
72 }
73
74 RESULT eServiceFactoryFS::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
75 {
76         ptr = m_service_information;
77         return 0;
78 }
79
80 RESULT eServiceFactoryFS::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
81 {
82         ptr = 0;
83         return -1;
84 }
85
86 // eServiceFS
87
88 DEFINE_REF(eServiceFS);
89
90 eServiceFS::eServiceFS(const char *path): path(path)
91 {
92         m_list_valid = 0;
93 }
94
95 eServiceFS::~eServiceFS()
96 {
97 }
98
99 int lower(char c)
100 {
101         return std::tolower(static_cast<unsigned char>(c));
102 }
103
104 RESULT eServiceFS::getContent(std::list<eServiceReference> &list, bool sorted)
105 {
106         DIR *d=opendir(path.c_str());
107         if (!d)
108                 return -errno;
109         while (dirent *e=readdir(d))
110         {
111                 if (!(strcmp(e->d_name, ".") && strcmp(e->d_name, "..")))
112                         continue;
113                 
114                 std::string filename;
115                 
116                 filename = path;
117                 filename += e->d_name;
118                 
119                 struct stat s;
120                 if (::stat(filename.c_str(), &s) < 0)
121                         continue;
122                 
123                 if (S_ISDIR(s.st_mode))
124                         filename += "/";
125                 
126                 if (S_ISDIR(s.st_mode))
127                 {
128                         eServiceReference service(eServiceFactoryFS::id, 
129                                 eServiceReference::isDirectory|
130                                 eServiceReference::canDescent|eServiceReference::mustDescent|
131                                 eServiceReference::shouldSort|eServiceReference::sort1,
132                                 filename);
133                         service.data[0] = 1;
134                         list.push_back(service);
135                 } else
136                 {
137                         size_t e = filename.rfind('.');
138                         std::string extension = (e != std::string::npos) ? filename.substr(e) : "";
139                         std::transform(extension.begin(), extension.end(), extension.begin(), lower);
140                         int type = -1;
141                         
142                         if (extension == ".ts")
143                                 type = eServiceFactoryDVB::id;
144                         else if (extension == ".mp3")
145                                 type = 0x1001;
146                         else if (extension == ".ogg")
147                                 type = 0x1001;
148                         else if (extension == ".mpg")
149                                 type = 0x1001;
150                         else if (extension == ".vob")
151                                 type = 0x1001;
152                         else if (extension == ".wav" || extension == ".wave")
153                                 type = 0x1001;
154                         else if (extension == ".m3u" || extension == ".pls" || extension == ".e2pls")
155                                 type = 4098; // ?? this id is not defined in any service handler, just in python code.
156                         
157                         if (type != -1)
158                         {
159                                 eServiceReference service(type,
160                                         0,
161                                         filename);
162                                 service.data[0] = 0;
163                                 list.push_back(service);
164                         }
165                 }
166         }
167         closedir(d);
168
169         if (sorted)
170                 list.sort(iListableServiceCompare(this));
171
172         return 0;
173 }
174
175 //   The first argument of this function is a format string to specify the order and
176 //   the content of the returned list
177 //   useable format options are
178 //   R = Service Reference (as swig object .. this is very slow)
179 //   S = Service Reference (as python string object .. same as ref.toString())
180 //   C = Service Reference (as python string object .. same as ref.toCompareString())
181 //   N = Service Name (as python string object)
182 //   when exactly one return value per service is selected in the format string,
183 //   then each value is directly a list entry
184 //   when more than one value is returned per service, then the list is a list of
185 //   python tuples
186 //   unknown format string chars are returned as python None values !
187 PyObject *eServiceFS::getContent(const char* format, bool sorted)
188 {
189         ePyObject ret;
190         std::list<eServiceReference> tmplist;
191         int retcount=1;
192
193         if (!format || !(retcount=strlen(format)))
194                 format = "R"; // just return service reference swig object ...
195
196         if (!getContent(tmplist, sorted))
197         {
198                 int services=tmplist.size();
199                 ePtr<iStaticServiceInformation> sptr;
200                 eServiceCenterPtr service_center;
201
202                 if (strchr(format, 'N'))
203                         eServiceCenter::getPrivInstance(service_center);
204
205                 ret = PyList_New(services);
206                 std::list<eServiceReference>::iterator it(tmplist.begin());
207
208                 for (int cnt=0; cnt < services; ++cnt)
209                 {
210                         eServiceReference &ref=*it++;
211                         ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
212                         for (int i=0; i < retcount; ++i)
213                         {
214                                 ePyObject tmp;
215                                 switch(format[i])
216                                 {
217                                 case 'R':  // service reference (swig)object
218                                         tmp = NEW_eServiceReference(ref);
219                                         break;
220                                 case 'C':  // service reference compare string
221                                         tmp = PyString_FromString(ref.toCompareString().c_str());
222                                         break;
223                                 case 'S':  // service reference string
224                                         tmp = PyString_FromString(ref.toString().c_str());
225                                         break;
226                                 case 'N':  // service name
227                                         if (service_center)
228                                         {
229                                                 service_center->info(ref, sptr);
230                                                 if (sptr)
231                                                 {
232                                                         std::string name;
233                                                         sptr->getName(ref, name);
234                                                         if (name.length())
235                                                                 tmp = PyString_FromString(name.c_str());
236                                                 }
237                                         }
238                                         if (!tmp)
239                                                 tmp = PyString_FromString("<n/a>");
240                                         break;
241                                 default:
242                                         if (tuple)
243                                         {
244                                                 tmp = Py_None;
245                                                 Py_INCREF(Py_None);
246                                         }
247                                         break;
248                                 }
249                                 if (tmp)
250                                 {
251                                         if (tuple)
252                                                 PyTuple_SET_ITEM(tuple, i, tmp);
253                                         else
254                                                 PyList_SET_ITEM(ret, cnt, tmp);
255                                 }
256                         }
257                         if (tuple)
258                                 PyList_SET_ITEM(ret, cnt, tuple);
259                 }
260         }
261         return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
262 }
263
264 RESULT eServiceFS::getNext(eServiceReference &ptr)
265 {
266         if (!m_list_valid)
267         {
268                 m_list_valid = 1;
269                 int res = getContent(m_list);
270                 if (res)
271                         return res;
272         }
273         
274         if (!m_list.size())
275         {
276                 ptr = eServiceReference();
277                 return -ERANGE;
278         }
279         
280         ptr = m_list.front();
281         m_list.pop_front();
282         return 0;
283 }
284
285 int eServiceFS::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
286 {
287                 /* directories first */
288         if ((a.flags & ~b.flags) & eServiceReference::isDirectory)
289                 return 1;
290         else if ((~a.flags & b.flags) & eServiceReference::isDirectory)
291                 return 0;
292                 /* sort by filename */
293         else
294                 return a.path < b.path;
295 }
296
297 RESULT eServiceFS::startEdit(ePtr<iMutableServiceList> &res)
298 {
299         res = 0;
300         return -1;
301 }
302
303 eAutoInitPtr<eServiceFactoryFS> init_eServiceFactoryFS(eAutoInitNumbers::service+1, "eServiceFactoryFS");