36ce9f4093b25c0ac694e912f459196144a06049
[enigma2.git] / lib / python / Plugins / Extensions / SocketMMI / src / socket_mmi.cpp
1 #include "socket_mmi.h"
2
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <sys/ioctl.h>
6
7 #include <lib/base/ebase.h>
8 #include <lib/base/init.h>
9 #include <lib/base/init_num.h>
10 #include <lib/base/eerror.h>
11 #include <lib/base/estring.h>
12 #include <lib/dvb_ci/dvbci_session.h>
13
14 #define MAX_LENGTH_BYTES 4
15 #define MIN_LENGTH_BYTES 1
16 //#define MMIDEBUG
17
18 eSocket_UI *eSocket_UI::instance;
19
20 eSocket_UI::eSocket_UI()
21         :eMMI_UI(1)
22 {
23         ASSERT(!instance);
24         instance = this;
25         CONNECT(handler.mmi_progress, eMMI_UI::processMMIData);
26 }
27
28 eSocket_UI *eSocket_UI::getInstance()
29 {
30         return instance;
31 }
32
33 void eSocket_UI::setInit(int)
34 {
35         //NYI
36 }
37
38 void eSocket_UI::setReset(int)
39 {
40         //NYI
41 }
42
43 int eSocket_UI::startMMI(int)
44 {
45         unsigned char buf[]={0x9F,0x80,0x22,0x00};  // ENTER MMI
46         if (handler.send_to_mmisock( buf, 4 ))
47         {
48                 eDebug("eSocket_UI::startMMI failed");
49                 return -1;
50         }
51         return 0;
52 }
53
54 int eSocket_UI::stopMMI(int)
55 {
56         unsigned char buf[]={0x9F,0x88,0x00,0x00};  // CLOSE MMI
57         if (handler.send_to_mmisock( buf, 4 ))
58         {
59                 eDebug("eSocket_UI::stopMMI failed");
60                 return -1;
61         }
62         return 0;
63 }
64
65 int eSocket_UI::answerMenu(int, int answer)
66 {
67         unsigned char data[]={0x9f,0x88,0x0B,0x01,0x00};
68         data[4] = answer & 0xff;
69         if (handler.send_to_mmisock( data, 5 ))
70         {
71                 eDebug("eSocket_UI::answerMenu failed");
72                 return -1;
73         }
74         return 0;
75 }
76
77 int eSocket_UI::answerEnq(int, char *answer)
78 {
79         unsigned int len = strlen(answer);
80         unsigned char data[4+len+MAX_LENGTH_BYTES];
81         data[0] = 0x9f;
82         data[1] = 0x88;
83         data[2] = 0x08;
84         int LengthBytes=eDVBCISession::buildLengthField(data+3, len+1);
85         data[3+LengthBytes] = 0x01;
86         memcpy(data+4+LengthBytes, answer, len);
87         if (handler.send_to_mmisock( data, len+4+LengthBytes ))
88         {
89                 eDebug("eSocket_UI::answerEnq failed");
90                 return -1;
91         }
92         return 0;
93 }
94
95 int eSocket_UI::cancelEnq(int)
96 {
97         unsigned char data[]={0x9f,0x88,0x08,0x01,0x00};
98         if (handler.send_to_mmisock( data, 5 ))
99         {
100                 eDebug("eSocket_UI::cancelEnq failed");
101                 return -1;
102         }
103         return 0;
104 }
105
106 int eSocket_UI::getState(int)
107 {
108         return handler.connected() ? 2 : 0;
109 }
110
111 int eSocket_UI::getMMIState(int)
112 {
113         return handler.connected();
114 }
115
116 //FIXME: correct "run/startlevel"
117 eAutoInitP0<eSocket_UI> init_socketui(eAutoInitNumbers::rc, "Socket MMI");
118
119 int eSocketMMIHandler::send_to_mmisock( void* buf, size_t len)
120 {
121         int ret = write(connfd, buf, len);
122         if ( ret < 0 )
123                 eDebug("[eSocketMMIHandler] write (%m)");
124         else if ( (uint)ret != len )
125                 eDebug("[eSocketMMIHandler] only %d bytes sent.. %d bytes should be sent", ret, len );
126         else
127                 return 0;
128         return ret;
129 }
130
131 eSocketMMIHandler::eSocketMMIHandler()
132         :buffer(512), connfd(-1), connsn(0), sockname("/tmp/mmi.socket"), name(0)
133 {
134         memset(&servaddr, 0, sizeof(struct sockaddr_un));
135         servaddr.sun_family = AF_UNIX;
136         unlink(sockname);
137         strcpy(servaddr.sun_path, sockname);
138         clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path);
139         if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
140         {
141                 eDebug("[eSocketMMIHandler] socket (%m)");
142                 return;
143         }
144
145         int val = 1;
146         if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1)
147                 eDebug("[eSocketMMIHandler] SO_REUSEADDR (%m)");
148         else if ((val = fcntl(listenfd, F_GETFL)) == -1)
149                 eDebug("[eSocketMMIHandler] F_GETFL (%m)");
150         else if (fcntl(listenfd, F_SETFL, val | O_NONBLOCK) == -1)
151                 eDebug("[eSocketMMIHandler] F_SETFL (%m)");
152         else if (bind(listenfd, (struct sockaddr *) &servaddr, clilen) == -1)
153                 eDebug("[eSocketMMIHandler] bind (%m)");
154         else if (listen(listenfd, 0) == -1)
155                 eDebug("[eSocketMMIHandler] listen (%m)");
156         else {
157                 listensn = new eSocketNotifier( eApp, listenfd, POLLIN );
158                 listensn->start();
159                 CONNECT( listensn->activated, eSocketMMIHandler::listenDataAvail );
160                 eDebug("[eSocketMMIHandler] created successfully");
161                 return;
162         }
163
164         close(listenfd);
165         listenfd = -1;
166 }
167
168 #define CMD_SET_NAME "\x01\x02\x03\x04"
169
170 void eSocketMMIHandler::listenDataAvail(int what)
171 {
172         if (what & POLLIN) {
173                 if ( connsn ) {
174                         eDebug("[eSocketMMIHandler] connsn != NULL");
175                         return;
176                 }
177                 connfd = accept(listenfd, (struct sockaddr *) &servaddr, (socklen_t *) &clilen);
178                 if (connfd == -1) {
179                         eDebug("[eSocketMMIHandler] accept (%m)");
180                         return;
181                 }
182
183                 int val;
184                 if ((val = fcntl(connfd, F_GETFL)) == -1)
185                         eDebug("[eSocketMMIHandler] F_GETFL (%m)");
186                 else if (fcntl(connfd, F_SETFL, val | O_NONBLOCK) == -1)
187                         eDebug("[eSocketMMIHandler] F_SETFL (%m)");
188                 else {
189                         connsn = new eSocketNotifier( eApp, connfd, POLLIN|POLLHUP|POLLERR );
190                         CONNECT( connsn->activated, eSocketMMIHandler::connDataAvail );
191                         return;
192                 }
193
194                 close(connfd);
195                 connfd = -1;
196         }
197 }
198
199 void eSocketMMIHandler::connDataAvail(int what)
200 {
201         if (what & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
202                 char msgbuffer[4096];
203                 ssize_t length = read(connfd, msgbuffer, sizeof(msgbuffer));
204
205                 if (length == -1) {
206                         if (errno != EAGAIN && errno != EINTR && errno != EBUSY) {
207                                 eDebug("[eSocketMMIHandler] read (%m)");
208                                 what |= POLLERR;
209                         }
210                 } else if (length == 0){
211                         what |= POLLHUP;
212                 } else if ((!name) && (length > 4) && (!memcmp(msgbuffer, CMD_SET_NAME, 4))) {
213                         length -= 4;
214                         delete [] name;
215                         name = new char[length + 1];
216                         memcpy(name, &msgbuffer[4], length);
217                         name[length] = '\0';
218                         eDebug("MMI NAME %s", name);
219                 } else {
220                         int len = length;
221                         unsigned char *data = (unsigned char*)msgbuffer;
222                         int clear = 1;
223         // If a new message starts, then the previous message
224         // should already have been processed. Otherwise the
225         // previous message was incomplete and should therefore
226         // be deleted.
227                         if ((len >= 1) && (data[0] != 0x9f))
228                                 clear = 0;
229                         if ((len >= 2) && (data[1] != 0x88))
230                                 clear = 0;
231                         if (clear)
232                         {
233                                 buffer.clear();
234 #ifdef MMIDEBUG
235                                 eDebug("clear buffer");
236 #endif
237                         }
238 #ifdef MMIDEBUG
239                         eDebug("Put to buffer:");
240                         for (int i=0; i < len; ++i)
241                                 eDebugNoNewLine("%02x ", data[i]);
242                         eDebug("\n--------");
243 #endif
244                         buffer.write( data, len );
245
246                         while ( buffer.size() >= (3 + MIN_LENGTH_BYTES) )
247                         {
248                                 unsigned char tmp[3+MAX_LENGTH_BYTES];
249                                 buffer.peek(tmp, 3+MIN_LENGTH_BYTES);
250                                 if (tmp[0] != 0x9f || tmp[1] != 0x88)
251                                 {
252                                         buffer.skip(1);
253 #ifdef MMIDEBUG
254                                         eDebug("skip %02x", tmp[0]);
255 #endif
256                                         continue;
257                                 }
258                                 if (tmp[3] & 0x80) {
259                                         int peekLength = (tmp[3] & 0x7f) + 4;
260                                         if (buffer.size() < peekLength)
261                                                 continue;
262                                         buffer.peek(tmp, peekLength);
263                                 }
264                                 int size=0;
265                                 int LengthBytes=eDVBCISession::parseLengthField(tmp+3, size);
266                                 int messageLength = 3+LengthBytes+size;
267                                 if ( buffer.size() >= messageLength )
268                                 {
269                                         unsigned char dest[messageLength];
270                                         buffer.read(dest, messageLength);
271 #ifdef MMIDEBUG
272                                         eDebug("dump mmi:");
273                                         for (int i=0; i < messageLength; ++i)
274                                                 eDebugNoNewLine("%02x ", dest[i]);
275                                         eDebug("\n--------");
276 #endif
277                                         /*emit*/ mmi_progress(0, dest, (const void*)(dest+3+LengthBytes), messageLength-3-LengthBytes);
278                                 }
279                         }
280                 }
281         }
282
283         if (what & (POLLERR | POLLHUP)) {
284                 eDebug("pollhup/pollerr");
285                 closeConn();
286                 /*emit*/ mmi_progress(0, (const unsigned char*)"\x9f\x88\x00", "\x00", 1);
287         }
288 }
289
290 void eSocketMMIHandler::closeConn()
291 {
292         if ( connfd != -1 )
293         {
294                 close(connfd);
295                 connfd=-1;
296         }
297         if ( connsn )
298         {
299                 delete connsn;
300                 connsn=0;
301         }
302         if ( name )
303         {
304                 delete [] name;
305                 name=0;
306         }
307 }
308
309 eSocketMMIHandler::~eSocketMMIHandler()
310 {
311         closeConn();
312         delete listensn;
313         unlink(sockname);
314 }
315
316 extern "C" {
317
318 static PyObject *
319 socketmmi_get_socket_state_changed_cb_list(PyObject *self)
320 {
321         return eSocket_UI::getInstance()->socketStateChanged.get();
322 }
323
324 static PyObject *
325 socketmmi_set_init(PyObject *self, PyObject *args)
326 {
327         int slot;
328         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
329                 return NULL;
330         eSocket_UI::getInstance()->setInit(slot);
331         Py_RETURN_NONE;
332 }
333
334 static PyObject *
335 socketmmi_set_reset(PyObject *self, PyObject *args)
336 {
337         int slot;
338         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
339                 return NULL;
340         eSocket_UI::getInstance()->setReset(slot);
341         Py_RETURN_NONE;
342 }
343
344 static PyObject *
345 socketmmi_available_mmi(PyObject *self, PyObject *args)
346 {
347         int slot;
348         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
349                 return NULL;
350         return PyInt_FromLong(eSocket_UI::getInstance()->availableMMI(slot));
351 }
352
353 static PyObject *
354 socketmmi_get_mmi_screen(PyObject *self, PyObject *args)
355 {
356         int slot;
357         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
358                 return NULL;
359         return eSocket_UI::getInstance()->getMMIScreen(slot);
360 }
361
362 static PyObject *
363 socketmmi_start_mmi(PyObject *self, PyObject *args)
364 {
365         int slot;
366         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
367                 return NULL;
368         return PyInt_FromLong(eSocket_UI::getInstance()->startMMI(slot));
369 }
370
371 static PyObject *
372 socketmmi_stop_mmi(PyObject *self, PyObject *args)
373 {
374         int slot;
375         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
376                 return NULL;
377         return PyInt_FromLong(eSocket_UI::getInstance()->stopMMI(slot));
378 }
379
380 static PyObject *
381 socketmmi_answer_menu(PyObject *self, PyObject *args)
382 {
383         int slot, answer;
384         if (PyTuple_Size(args) != 2 || !PyArg_ParseTuple(args, "ii", &slot, &answer))
385                 return NULL;
386         return PyInt_FromLong(eSocket_UI::getInstance()->answerMenu(slot, answer));
387 }
388
389 static PyObject *
390 socketmmi_answer_enq(PyObject *self, PyObject *args)
391 {
392         int slot;
393         char *answer;
394         if (PyTuple_Size(args) != 2 || !PyArg_ParseTuple(args, "is", &slot, &answer))
395                 return NULL;
396         return PyInt_FromLong(eSocket_UI::getInstance()->answerEnq(slot, answer));
397 }
398
399 static PyObject *
400 socketmmi_cancel_enq(PyObject *self, PyObject *args)
401 {
402         int slot;
403         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
404                 return NULL;
405         return PyInt_FromLong(eSocket_UI::getInstance()->cancelEnq(slot));
406 }
407
408 static PyObject *
409 socketmmi_get_state(PyObject *self, PyObject *args)
410 {
411         int slot;
412         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
413                 return NULL;
414         return PyInt_FromLong(eSocket_UI::getInstance()->getState(slot));
415 }
416
417 static PyObject *
418 socketmmi_get_mmi_state(PyObject *self, PyObject *args)
419 {
420         int slot;
421         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
422                 return NULL;
423         return PyInt_FromLong(eSocket_UI::getInstance()->getMMIState(slot));
424 }
425
426 static PyObject *
427 socketmmi_get_name(PyObject *self, PyObject *args)
428 {
429         int slot;
430         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot))
431                 return NULL;
432         return PyString_FromString(eSocket_UI::getInstance()->getName(slot));
433 }
434
435 static PyMethodDef module_methods[] = {
436         {"getSocketStateChangedCallbackList", (PyCFunction)socketmmi_get_socket_state_changed_cb_list, METH_NOARGS,
437          "get socket state change callback list"
438         },
439         {"setInit", (PyCFunction)socketmmi_set_init, METH_VARARGS,
440          "set init"
441         },
442         {"setReset", (PyCFunction)socketmmi_set_reset, METH_VARARGS,
443          "set reset"
444         },
445         {"availableMMI", (PyCFunction)socketmmi_available_mmi, METH_VARARGS,
446          "available mmi"
447         },
448         {"getMMIScreen", (PyCFunction)socketmmi_get_mmi_screen, METH_VARARGS,
449          "get mmi screen"
450         },
451         {"startMMI", (PyCFunction)socketmmi_start_mmi, METH_VARARGS,
452          "start mmi"
453         },
454         {"stopMMI", (PyCFunction)socketmmi_stop_mmi, METH_VARARGS,
455          "start mmi"
456         },
457         {"answerMenu", (PyCFunction)socketmmi_answer_menu, METH_VARARGS,
458          "answer menu"
459         },
460         {"answerEnq", (PyCFunction)socketmmi_answer_enq, METH_VARARGS,
461          "answer enq"
462         },
463         {"cancelEnq", (PyCFunction)socketmmi_cancel_enq, METH_VARARGS,
464          "cancel enq"
465         },
466         {"getState", (PyCFunction)socketmmi_get_state, METH_VARARGS,
467          "get state of socket"
468         },
469         {"getMMIState", (PyCFunction)socketmmi_get_mmi_state, METH_VARARGS,
470          "get state of mmi"
471         },
472         {"getName", (PyCFunction)socketmmi_get_name, METH_VARARGS,
473          "get name of socket user"
474         },
475         {NULL, NULL, 0, NULL}   /* Sentinel */
476 };
477
478 PyMODINIT_FUNC
479 initsocketmmi(void)
480 {
481         Py_InitModule3("socketmmi", module_methods,
482                 "Module that implements mmi via unix domain socket.");
483 }
484 };