Add support for tizen.account which will be automotically populated
[profile/ivi/sockdrawer.git] / main.c
1 #include <Ecore.h>
2 #include <E_DBus.h>
3 #include <Efreet.h>
4 #include <Eina.h>
5 #include <getopt.h>
6 #include <jansson.h>
7 #include <libwebsockets.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <sys/inotify.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13
14 enum sockdrawer_protocols {
15     PROTOCOL_HTTP = 0,
16     PROTOCOL_APP_LIST,
17     PROTOCOL_DIALER,
18     SOCKDRAWER_PROTOCOL_COUNT
19 };
20
21 #ifdef INSTALL_DATADIR
22 #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/sockdrawer"
23 #else
24 #define LOCAL_RESOURCE_PATH "."
25 #endif
26
27 #define DEFAULTCONTENT LOCAL_RESOURCE_PATH"/index.html"
28 #define DEFAULTICON LOCAL_RESOURCE_PATH"/default.png"
29
30 #define APPDIR "/usr/share/applications"
31
32 struct libwebsocket_context *context;
33
34 E_DBus_Connection *bus;
35
36 json_t *app_list = NULL;
37 char *apps_directory = NULL;
38
39 json_t *event_queue = NULL;
40
41 char *voicecallmanager_path = NULL;
42
43 #define MAX_POLL_ELEMENTS 100
44 struct pollfd pollfds[100];
45 int count_pollfds = 0;
46
47 void handle_command(json_t *o);
48 static int callback_http(struct libwebsocket_context *context, 
49                          struct libwebsocket *wsi,
50                          enum libwebsocket_callback_reasons reason, void *user, 
51                          void *in, size_t len);
52 void send_app_list(struct libwebsocket *socket);
53 static int callback_app_list(struct libwebsocket_context *context,
54                              struct libwebsocket *wsi,
55                              enum libwebsocket_callback_reasons reason,
56                              void *user, void *in, size_t len);
57 static Eina_Bool get_websocket_event(void *data);
58 static int callback_dialer(struct libwebsocket_context *context,
59                            struct libwebsocket *wsi,
60                            enum libwebsocket_callback_reasons reason,
61                            void *user, void *in, size_t len);
62
63 /*
64  * Per instance data
65  */
66 struct per_session_data__app_list {
67     int placeholder;
68 };
69 struct per_session_data__dialer {
70     int placeholder;
71 };
72
73 static struct libwebsocket_protocols protocols[] = {
74     {
75         "http-only",
76         callback_http,
77         0
78     },
79    {
80         "app-list-protocol",
81         callback_app_list,
82         sizeof(struct per_session_data__app_list),
83     },
84    {
85         "dialer-protocol",
86         callback_dialer,
87         sizeof(struct per_session_data__dialer),
88     },
89     {
90         NULL, NULL, 0
91     }
92 };
93
94 /* libwebsocket callback for handling normal http request. We use this */
95 /* to implementa a rudamentary webserver. */
96 static int 
97 callback_http(struct libwebsocket_context *context, 
98               struct libwebsocket *wsi,
99               enum libwebsocket_callback_reasons reason, void *user, 
100               void *in, size_t len)
101 {
102     char client_name[128];
103     char client_ip[128];
104     char filename[256];
105     int n;
106     struct stat info;
107
108     switch (reason) {
109     case LWS_CALLBACK_HTTP:
110         if (in && ((char *)in)[0] == '/' && !strstr(in, "..")) {
111             if (strstr(in, "/icon/") == in) {
112                 /* virtual directory used for serving up system icons */
113
114                 char *icon = (char *)(in + 6);
115                 const char *path = efreet_icon_path_find(getenv("E_ICON_THEME"), 
116                                                          (const char *)icon, 128);
117                 if (!path) {
118                     path = efreet_icon_path_find("default", icon, 128);
119                     if (!path) {
120                         path = efreet_icon_path_find("hicolor", icon, 128);
121                         if (!path) {
122                             if (icon[0] == '/' && !stat(icon, &info) && S_ISREG(info.st_mode))
123                                 path = icon;
124                             else {
125                                 fprintf(stderr, "Can not find icon: %s\n", icon);
126                                 path = DEFAULTICON;
127                             }
128                         }
129                     }
130                 }
131
132                 libwebsockets_serve_http_file(wsi, path, 
133                                               (const char *)efreet_mime_type_get((char *)path));
134             } else {
135                 snprintf(filename, 256, "%s/%s", LOCAL_RESOURCE_PATH, (char *)in + 1);
136                 if (strlen((char *)in) == 1)
137                     /* serve up default content */
138                     libwebsockets_serve_http_file(wsi, DEFAULTCONTENT, "text/html");
139                 else if (!stat(filename, &info) && S_ISREG(info.st_mode))
140                     libwebsockets_serve_http_file(wsi, filename, 
141                                                   (const char *)efreet_mime_type_get((char *)in));
142                 else
143                     fprintf(stderr, "Failed to find content: %s\n", (char *)in);
144             }
145         } else {
146             fprintf(stderr, "Invalid request \'%s\'\n", (char *)in);
147         }
148         break;
149
150     case LWS_CALLBACK_ADD_POLL_FD:
151         pollfds[count_pollfds].fd = (int)(long)user;
152         pollfds[count_pollfds].events = (int)len;
153         pollfds[count_pollfds++].revents = 0;
154         break;
155
156     case LWS_CALLBACK_DEL_POLL_FD:
157         for (n = 0; n < count_pollfds; n++)
158             if (pollfds[n].fd == (int)(long)user)
159                 while (n < count_pollfds) {
160                     pollfds[n] = pollfds[n + 1];
161                     n++;
162                 }
163         count_pollfds--;
164         break;
165
166     case LWS_CALLBACK_SET_MODE_POLL_FD:
167         for (n = 0; n < count_pollfds; n++)
168             if (pollfds[n].fd == (int)(long)user)
169                 pollfds[n].events |= (int)(long)len;
170         break;
171
172     case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
173         for (n = 0; n < count_pollfds; n++)
174             if (pollfds[n].fd == (int)(long)user)
175                 pollfds[n].events &= ~(int)(long)len;
176         break;
177
178     default:
179         break;
180     }
181     
182     return 0;
183 }
184
185 void
186 dial_reply(void *data, DBusMessage *reply, DBusError *error)
187 {
188     if (dbus_error_is_set(error)) {
189         fprintf(stderr, "Error: %s - %s\n", error->name, error->message);
190         return;
191     }
192 }
193
194 /* libwebsocket callback for the 'protocol-dialer' protocol */
195 static int
196 callback_dialer(struct libwebsocket_context *context,
197                 struct libwebsocket *wsi,
198                 enum libwebsocket_callback_reasons reason,
199                 void *user, void *in, size_t len)
200 {
201     json_t *o = NULL;
202     int i;
203
204     switch (reason) {
205     case LWS_CALLBACK_BROADCAST:
206         /* 
207          * This is triggered on all open websocket connections
208          * when libwebsocket_broadcast is called. For this 
209          * protocol we ignore the 'in' paramter and send out
210          * the pending event queue
211          */
212         if (in) {
213             unsigned char *b = malloc(LWS_SEND_BUFFER_PRE_PADDING + 
214                                       strlen((char *)in) + 
215                                       LWS_SEND_BUFFER_POST_PADDING);
216             unsigned char *p = b + LWS_SEND_BUFFER_PRE_PADDING;
217             int n = sprintf((char *)p, "%s", (char *)in);
218
219             libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
220
221             free(b);
222         }
223         break;
224
225     case LWS_CALLBACK_ESTABLISHED:
226         if (voicecallmanager_path) {
227             /* inform any connections about the addition of the modem */
228             json_t *o = json_object();
229             json_object_set(o, "ModemAdded", json_string(voicecallmanager_path));
230             char *dump = json_dumps(o, 0);
231
232             unsigned char *b = malloc(LWS_SEND_BUFFER_PRE_PADDING + 
233                                       strlen(dump) + 
234                                       LWS_SEND_BUFFER_POST_PADDING);
235             unsigned char *p = b + LWS_SEND_BUFFER_PRE_PADDING;
236             int n = sprintf((char *)p, "%s", dump);
237
238             libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
239             free(b);
240             free(dump);
241         }
242
243     case LWS_CALLBACK_RECEIVE:
244         /* 
245          * The other end of the websocket is sending us text
246          * so attempt to parse that text as a JSON object providing
247          * either a single command object or an array of command
248          * objects.
249          */
250         if (in && (o = json_loads((char *)in, 0, NULL))) {
251             if (json_is_array(o)) {
252                 for (i = 0; i < json_array_size(o); i++)
253                     handle_command(json_array_get(o, i));
254                 json_array_clear(o);
255             } else {
256                 handle_command(o);
257                 json_object_clear(o);
258             }
259         }
260         break;
261
262     default:
263         break;
264     }
265
266     return 0;
267 }
268
269 /* Write a serialized JSON object containing */
270 /* a list of objects each describing an application */
271 void send_app_list(struct libwebsocket *socket) 
272 {
273     /* 
274      * WARNING: libwebsockets requires prefixing and post
275      *          fixing the send buffer with enough space
276      *          for the library to insert required websocket
277      *          protocol information.
278      *          Ignoring this will result in segfaults.
279      */
280     char *dump = json_dumps(app_list, 0);
281     unsigned char *b = malloc(LWS_SEND_BUFFER_PRE_PADDING + 
282                               strlen(dump) + 
283                               LWS_SEND_BUFFER_POST_PADDING);
284     unsigned char *p = b + LWS_SEND_BUFFER_PRE_PADDING;
285     int n = sprintf((char *)p, "%s", dump);
286
287     libwebsocket_write(socket, p, n, LWS_WRITE_TEXT);
288
289     free(dump);
290     free(b);
291 }
292
293 /* command object parser */
294 void handle_command(json_t *o)
295 {
296     const char *cmd = json_string_value(json_object_get(o, "cmd"));
297     if (!cmd)
298         return;
299
300     json_t *tmp;
301     if (strncmp(cmd, "launch", 6) == 0 && (tmp = json_object_get(o, "index"))) {
302         int index = json_integer_value(tmp);
303         json_t *app = json_array_get(app_list, index);
304         if (!app)
305             return;
306
307         json_t *exec = json_object_get(app, "exec");
308         if (!exec)
309             return;
310         
311         ecore_exe_run(json_string_value(exec), NULL);
312     } else if (strncmp(cmd, "makeCall", 8) == 0 && 
313                (tmp = json_object_get(o, "remotePartyId"))) {
314         const char *remotePartyId = json_string_value(tmp);
315         const char *hideCallerId = "";
316
317         DBusMessage *msg;
318         msg = dbus_message_new_method_call(
319                                            "org.ofono",
320                                            voicecallmanager_path,
321                                            "org.ofono.VoiceCallManager",
322                                            "Dial"
323                                            );
324         dbus_message_append_args(msg, 
325                                  DBUS_TYPE_STRING, &remotePartyId, 
326                                  DBUS_TYPE_INVALID);
327         dbus_message_append_args(msg, 
328                                  DBUS_TYPE_STRING, &hideCallerId,
329                                  DBUS_TYPE_INVALID);
330         e_dbus_message_send(bus, msg, dial_reply, -1, NULL);
331     } else if (strncmp(cmd, "end", 3) == 0) {
332         DBusMessage *msg;
333         msg = dbus_message_new_method_call(
334                                            "org.ofono",
335                                            voicecallmanager_path,
336                                            "org.ofono.VoiceCallManager",
337                                            "HangupAll"
338                                            );
339         e_dbus_message_send(bus, msg, dial_reply, -1, NULL);
340
341     }
342 }
343
344 /* libwebsocket callback for 'protocol-app-list' based websockets */
345 static int
346 callback_app_list(struct libwebsocket_context *context,
347                   struct libwebsocket *wsi,
348                   enum libwebsocket_callback_reasons reason,
349                   void *user, void *in, size_t len)
350 {
351     json_t *o = NULL;
352     int i;
353
354     switch (reason) {
355     case LWS_CALLBACK_BROADCAST:
356         /* 
357          * This is triggered on all open websocket connections
358          * when libwebsocket_broadcast is called. For this 
359          * protocol we only do one possible thing on broadcast
360          * so just ignore the incoming 'in' string and just
361          * send a new list of applications.
362          */
363     case LWS_CALLBACK_ESTABLISHED:
364         send_app_list(wsi);
365         break;
366
367     case LWS_CALLBACK_RECEIVE:
368         /* 
369          * The other end of the websocket is sending us text
370          * so attempt to parse that text as a JSON object providing
371          * either a single command object or an array of command
372          * objects.
373          */
374         if (in && (o = json_loads((char *)in, 0, NULL))) {
375             if (json_is_array(o)) {
376                 for (i = 0; i < json_array_size(o); i++)
377                     handle_command(json_array_get(o, i));
378                 json_array_clear(o);
379             } else {
380                 handle_command(o);
381                 json_object_clear(o);
382             }
383         }
384         break;
385
386     default:
387         break;
388     }
389
390     return 0;
391 }
392
393 void build_app_list(char *dir) {
394     Eina_Iterator *it;
395     const char *filename;
396     const Eina_File_Direct_Info *info;
397
398     json_array_clear(app_list);
399
400     int index = 0;
401     it = eina_file_ls(dir);
402     EINA_ITERATOR_FOREACH(it, filename)
403         {
404             if (!eina_str_has_suffix(filename, ".desktop"))
405                 continue;
406
407             Efreet_Desktop *desktop = efreet_desktop_get(filename);
408             if (!desktop || !desktop->name || !desktop->icon || !desktop->exec)
409                 continue;
410
411             json_t *o = json_object();
412             json_object_set(o, "id", json_integer(index++));
413             json_object_set(o, "version", json_string("0.1"));
414             json_object_set(o, "show", json_boolean(1));
415             json_object_set(o, "name", json_string(desktop->name));
416             json_object_set(o, "iconPath", json_string(desktop->icon));
417             json_object_set(o, "exec", json_string(desktop->exec));
418             json_array_append(app_list, o);
419         }
420     eina_iterator_free(it);
421 }
422
423 #define BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024)
424 static Eina_Bool poll_descriptors(void *data)
425 {
426     int n;
427     ssize_t len, i = 0;
428     char buff[BUFF_SIZE] = {0};
429
430     n = poll(pollfds, count_pollfds, 100);
431     if (n > -1) {
432         if (pollfds[0].revents) {
433             /* The first descriptor what inotify returns*/
434             len = read(pollfds[0].fd, buff, BUFF_SIZE);
435             while (i < len) {
436                 struct inotify_event *pevent = (struct inotify_event *)&buff[i];
437                 if (pevent->name && eina_str_has_suffix(pevent->name, ".desktop")) {
438                     build_app_list(apps_directory);
439
440                     /* Trigger the broadcast callback for all open connectinos */
441                     libwebsockets_broadcast(&protocols[PROTOCOL_APP_LIST], "x", 2);
442                     break;
443                 }
444
445                 i += sizeof(struct inotify_event) + pevent->len;
446             }
447         }
448         if (count_pollfds > 1) {
449             for (n = 1; n < count_pollfds; n++)
450                 if (pollfds[n].revents)
451                     libwebsocket_service_fd(context, &pollfds[n]);
452         }
453     }
454
455     return ECORE_CALLBACK_RENEW;
456 }
457
458 void call_properties_changed_cb(void *data, DBusMessage *msg)
459 {
460     DBusMessageIter iter, value;
461     const char *property, *v;
462     char *dump;
463     int n;
464     json_t *object;
465
466     dbus_message_iter_init(msg, &iter);
467     dbus_message_iter_get_basic(&iter, &property);
468
469     dbus_message_iter_next(&iter);
470     dbus_message_iter_recurse(&iter, &value);
471
472     dbus_message_iter_get_basic(&value, &v);
473
474     object = json_object();
475     json_object_set(object, property, json_string(v));
476     dump = json_dumps(object, 0);
477     libwebsockets_broadcast(&protocols[PROTOCOL_DIALER], dump, strlen(dump));
478     free(dump);
479 }
480
481 void modem_properties_changed_cb(void *data, DBusMessage *msg)
482 {
483     DBusMessageIter iter, values, entry;
484     const char *property, *v;
485     char *dump;
486     int n;
487     json_t *object;
488
489     dbus_message_iter_init(msg, &iter);
490     dbus_message_iter_get_basic(&iter, &property);
491
492     if (!strcasecmp(property, "Interfaces")) {
493         dbus_message_iter_next(&iter);
494         dbus_message_iter_recurse(&iter, &values);
495
496         while (dbus_message_iter_get_arg_type(&values) == DBUS_TYPE_ARRAY) {
497             DBusMessageIter variant;
498             dbus_message_iter_recurse(&iter, &entry);
499             dbus_message_iter_recurse(&entry, &variant);
500             if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_INVALID) {
501                 dbus_message_iter_get_basic(&variant, &v);
502                 if (!strcasecmp(v, "org.ofono.VoiceCallManager")) {
503                     object = json_object();
504                     json_object_set(object, "ModemAdded", json_string(dbus_message_get_path(msg)));
505                     dump = json_dumps(object, 0);
506                     libwebsockets_broadcast(&protocols[PROTOCOL_DIALER], dump, strlen(dump));
507                     free(dump);
508                 }
509             } else {
510                 // If the modem has removed all interfaces then its no longer
511                 // available for making calls
512                 object = json_object();
513                 json_object_set(object, "ModemRemoved", json_string(dbus_message_get_path(msg)));
514                 dump = json_dumps(object, 0);
515                 libwebsockets_broadcast(&protocols[PROTOCOL_DIALER], dump, strlen(dump));
516                 free(dump);                
517             }
518             dbus_message_iter_next(&values);
519         }
520     }
521 }
522
523 void call_added_cb(void *data, DBusMessage *msg)
524 {
525     DBusMessageIter iter, properties;
526     const char *path;
527
528     json_t *object = json_object();
529
530     dbus_message_iter_init(msg, &iter);
531     dbus_message_iter_get_basic(&iter, &path);
532
533     dbus_message_iter_next(&iter);
534     dbus_message_iter_recurse(&iter, &properties);
535
536     while (dbus_message_iter_get_arg_type(&properties) == DBUS_TYPE_DICT_ENTRY) {
537         DBusMessageIter entry, value;
538         const char *key, *v;
539
540         dbus_message_iter_recurse(&properties, &entry);
541         dbus_message_iter_get_basic(&entry, &key);
542
543         dbus_message_iter_next(&entry);
544         dbus_message_iter_recurse(&entry, &value);
545         
546         dbus_message_iter_get_basic(&value, &v);
547
548         json_object_set(object, key, json_string(v));
549
550         dbus_message_iter_next(&properties);
551     }
552
553     e_dbus_signal_handler_add(bus, 
554                               "org.ofono", 
555                               path,
556                               "org.ofono.VoiceCall", 
557                               "PropertyChanged", 
558                               call_properties_changed_cb, 
559                               NULL);
560
561     char *dump = json_dumps(object, 0);
562     libwebsockets_broadcast(&protocols[PROTOCOL_DIALER], dump, strlen(dump));
563     free(dump);
564 }
565
566 void call_removed_cb(void *data, DBusMessage *msg)
567 {
568     json_t *object = json_object();
569     json_object_set(object, "type", json_string("CallRemoved"));
570     char *dump = json_dumps(object, 0);
571     libwebsockets_broadcast(&protocols[PROTOCOL_DIALER], dump, strlen(dump));
572     free(dump);
573 }
574
575 void modem_added_cb(void *data, DBusMessage *msg)
576 {
577     DBusMessageIter iter;
578     const char *path;
579     
580     dbus_message_iter_init(msg, &iter);
581     dbus_message_iter_get_basic(&iter, &path);
582
583     json_t *object = json_object();
584     json_object_set(object, "ModemAdded", json_string(path));
585     char *dump = json_dumps(object, 0);
586     libwebsockets_broadcast(&protocols[PROTOCOL_DIALER], dump, strlen(dump));
587     free(dump);    
588 }
589
590 void modem_removed_cb(void *data, DBusMessage *msg)
591 {
592     DBusMessageIter iter;
593     const char *path;
594
595     dbus_message_iter_init(msg, &iter);
596     dbus_message_iter_get_basic(&iter, &path);
597
598     json_t *object = json_object();
599     json_object_set(object, "ModemRemoved", json_string(path));
600     char *dump = json_dumps(object, 0);
601     libwebsockets_broadcast(&protocols[PROTOCOL_DIALER], dump, strlen(dump));
602     free(dump);
603 }
604
605 void
606 get_modems_reply(void *data, DBusMessage *reply, DBusError *error)
607 {
608     DBusMessageIter iter, entry;
609     if (dbus_error_is_set(error)) {
610         fprintf(stderr, "Error: %s - %s\n", error->name, error->message);
611         return;
612     }
613
614     dbus_message_iter_init(reply, &iter);
615     if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
616         fprintf(stderr, "Unexpeced signature from ofono GetModems call\n");
617         return;
618     }
619
620     dbus_message_iter_recurse(&iter, &entry);
621     
622     while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) {
623         const char *path;
624         DBusMessageIter item, properties;
625
626         dbus_message_iter_recurse(&entry, &item);
627         dbus_message_iter_get_basic(&item, &path);
628
629         printf("registering %s\n", path);
630         e_dbus_signal_handler_add(bus, "org.ofono", 
631                                   path, "org.ofono.Modem", "PropertyChanged", 
632                                   modem_properties_changed_cb, (void *)strdup(path));
633         e_dbus_signal_handler_add(bus, "org.ofono", 
634                                   path, "org.ofono.VoiceCallManager", "CallAdded", 
635                                   call_added_cb, NULL);
636         e_dbus_signal_handler_add(bus, "org.ofono", 
637                                   path, "org.ofono.VoiceCallManager", 
638                                   "CallRemoved", 
639                                   call_removed_cb, NULL);
640
641         dbus_message_iter_next(&item);
642         dbus_message_iter_recurse(&item, &properties);
643
644         while (dbus_message_iter_get_arg_type(&properties) == DBUS_TYPE_DICT_ENTRY) {
645             const char *key;
646             DBusMessageIter interfaces, value, entry;
647
648             dbus_message_iter_recurse(&properties, &entry);
649             dbus_message_iter_get_basic(&entry, &key);
650
651             dbus_message_iter_next(&entry);
652             dbus_message_iter_recurse(&entry, &value);
653             
654             if (!strcasecmp(key, "Interfaces")) {
655                 dbus_message_iter_recurse(&value, &interfaces);
656                 while (dbus_message_iter_get_arg_type(&interfaces) == 
657                        DBUS_TYPE_STRING) {
658                     const char *iface;
659                     
660                     dbus_message_iter_get_basic(&interfaces, &iface);
661                     
662                     if (!strcasecmp(iface, "org.ofono.VoiceCallManager")) {
663                         if (voicecallmanager_path)
664                             free(voicecallmanager_path);
665                         voicecallmanager_path = strdup(path);
666
667                         /* inform any connections about the addition of the modem */
668                         json_t *o = json_object();
669                         json_object_set(o, "ModemAdded", json_string(path));
670                         char *dump = json_dumps(o, 0);
671                         libwebsockets_broadcast(&protocols[PROTOCOL_DIALER], dump, strlen(dump));
672                         free(dump);
673                     }
674
675                     dbus_message_iter_next(&interfaces);
676                 }
677             }
678
679             dbus_message_iter_next(&properties);
680         }
681
682         dbus_message_iter_next(&entry);
683     }
684 }
685
686 static struct option options[] = {
687     { "help",      no_argument,         NULL, 'h' },
688     { "port",      required_argument,   NULL, 'p' },
689     { "directory", required_argument,   NULL, 'd' },
690     { NULL, 0, 0, 0 }
691 };
692
693 int main(int argc, char **argv)
694 {
695     int fd;
696     int n = 0;
697     int port = 7681;
698     int opts = 0;
699
700     eina_init();
701     ecore_init();
702     e_dbus_init();
703     efreet_init();
704     efreet_mime_init();
705     ecore_app_args_set(argc, (const char **)argv);
706
707     /* parse command-line options */
708     while (n >= 0) {
709         n = getopt_long(argc, argv, "hp:d:", options, NULL);
710         if (n < 0)
711             continue;
712         switch (n) {
713         case 'd':
714             apps_directory = strdup(optarg);
715             break;
716         case 'p':
717             port = atoi(optarg);
718             break;
719         case 'h':
720             fprintf(stderr, "Usage: %s [--port=<p>] [--directory=<d>]\n", argv[0]);
721             exit(-1);
722         }
723     }
724     if (!apps_directory)
725         apps_directory = APPDIR;
726     
727     /* Initialize and build up the application list */
728     app_list = json_array();
729     build_app_list(apps_directory);
730
731     bus = e_dbus_bus_get(DBUS_BUS_SYSTEM);
732
733     /* Start listening for incoming phone calls */
734     DBusMessage *msg;
735     msg = dbus_message_new_method_call(
736                                        "org.ofono",
737                                        "/",
738                                        "org.ofono.Manager",
739                                        "GetModems"
740                                        );
741     e_dbus_message_send(bus, msg, get_modems_reply, -1, NULL);
742
743     e_dbus_signal_handler_add(bus, "org.ofono", "/", "org.ofono.Manager", "ModemAdded", 
744                               modem_added_cb, NULL);
745     e_dbus_signal_handler_add(bus, "org.ofono", "/", "org.ofono.Manager", "ModemRemoved", 
746                               modem_removed_cb, NULL);
747
748     /* Listen for updates on application desktop files*/
749     fd = inotify_init();
750     inotify_add_watch(fd, APPDIR, IN_CREATE | IN_DELETE | IN_MODIFY);
751     pollfds[0].fd = fd;
752     pollfds[0].events = POLLIN;
753     pollfds[0].revents = 0;
754     count_pollfds = 1;
755
756     /* Start listening for incoming websocket connections */
757     context = libwebsocket_create_context(port, NULL, protocols,
758                                           libwebsocket_internal_extensions,
759                                           NULL, NULL, -1, -1, opts);
760     if (context == NULL) {
761         fprintf(stderr, "libwebsocket init failed\n");
762         return -1;
763     }
764
765     ecore_idler_add(poll_descriptors, NULL);
766     
767     ecore_main_loop_begin();
768     
769     /* cleanup */
770     libwebsocket_context_destroy(context);
771     ecore_shutdown();
772     return 0;
773 }
774
775 /* Local Variables:      */
776 /* mode:c                */
777 /* c-basic-offset:4      */
778 /* indent-tabs-mode: nil */
779 /* End:                  */