stktest: Fixup message
[platform/upstream/ofono.git] / tools / stktest.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35
36 #include <gdbus.h>
37 #include <gatchat/gatserver.h>
38
39 #define OFONO_SERVICE   "org.ofono"
40 #define STKTEST_PATH    "/stktest"
41 #define STKTEST_ERROR   "org.ofono.stktest.Error"
42 #define OFONO_ERROR     "org.ofono.Error"
43 #define OFONO_MANAGER_INTERFACE         OFONO_SERVICE ".Manager"
44 #define OFONO_MODEM_INTERFACE           OFONO_SERVICE ".Modem"
45 #define OFONO_STK_INTERFACE             OFONO_SERVICE ".SimToolkit"
46 #define OFONO_STKAGENT_INTERFACE        OFONO_SERVICE ".SimToolkitAgent"
47
48 #define LISTEN_PORT     12765
49
50 enum test_state {
51         TEST_STATE_POWERING_UP = 1,
52         TEST_STATE_REGISTERING_AGENT,
53         TEST_STATE_RUNNING,
54         TEST_STATE_POWERING_DOWN,
55 };
56
57 static GMainLoop *main_loop = NULL;
58 static volatile sig_atomic_t __terminated = 0;
59
60 /* DBus related */
61 static DBusConnection *conn;
62 static gboolean ofono_running = FALSE;
63 static guint modem_changed_watch;
64 enum test_state state;
65
66 /* Emulator setup */
67 static guint server_watch;
68 static GAtServer *emulator;
69
70 /* Emulated modem state variables */
71 static int modem_mode = 0;
72
73 static gboolean create_tcp(void);
74
75 static const char *to_hex(const unsigned char *data, unsigned int len)
76 {
77         static char buf[512+1];
78         unsigned int i;
79
80         for (i = 0; i < len; i++)
81                 sprintf(buf + i * 2, "%02hhX", data[i]);
82
83         buf[i*2] = '\0';
84
85         return buf;
86 }
87
88 static void send_proactive_command(const unsigned char *pdu, unsigned int len)
89 {
90         char buf[1024];
91
92         sprintf(buf, "+CUSATP: %s", to_hex(pdu, len));
93         g_at_server_send_unsolicited(emulator, buf);
94 }
95
96 static DBusMessage *stktest_error_invalid_args(DBusMessage *msg)
97 {
98         return g_dbus_create_error(msg, STKTEST_ERROR ".InvalidArguments",
99                                         "Invalid arguments provided");
100 }
101
102 static DBusMessage *stktest_error_failed(DBusMessage *msg)
103 {
104         return g_dbus_create_error(msg, STKTEST_ERROR ".Failed",
105                                         "Operation failed");
106 }
107
108 static DBusMessage *stktest_error_end_session(DBusMessage *msg)
109 {
110         return g_dbus_create_error(msg, OFONO_ERROR ".EndSession",
111                                         "End Session Request");
112 }
113
114 static DBusMessage *stktest_error_go_back(DBusMessage *msg)
115 {
116         return g_dbus_create_error(msg, OFONO_ERROR ".GoBack",
117                                         "Go Back Request");
118 }
119
120 static DBusMessage *stktest_error_busy(DBusMessage *msg)
121 {
122         return g_dbus_create_error(msg, OFONO_ERROR ".Busy",
123                                         "UI Busy");
124 }
125
126 static DBusMessage *agent_release(DBusConnection *conn, DBusMessage *msg,
127                                         void *data)
128 {
129         g_print("Got Release\n");
130
131         return dbus_message_new_method_return(msg);
132 }
133
134 static DBusMessage *agent_display_text(DBusConnection *conn, DBusMessage *msg,
135                                         void *data)
136 {
137         const char *text;
138         unsigned char icon_id;
139         dbus_bool_t urgent;
140
141         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &text,
142                                                 DBUS_TYPE_BYTE, &icon_id,
143                                                 DBUS_TYPE_BOOLEAN, &urgent,
144                                                 DBUS_TYPE_INVALID) == FALSE)
145                 return stktest_error_invalid_args(msg);
146
147         g_print("Got DisplayText with: %s, %u, %d\n", text, icon_id, urgent);
148
149         return dbus_message_new_method_return(msg);
150 }
151
152 static void server_debug(const char *str, void *data)
153 {
154         g_print("%s: %s\n", (char *) data, str);
155 }
156
157 static void cgmi_cb(GAtServer *server, GAtServerRequestType type,
158                         GAtResult *cmd, gpointer user)
159 {
160         switch (type) {
161         case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
162                 g_at_server_send_info(server, "oFono", TRUE);
163                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
164                 break;
165         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
166                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
167                 break;
168         default:
169                 g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
170         };
171 }
172
173 static void cgmm_cb(GAtServer *server, GAtServerRequestType type,
174                         GAtResult *cmd, gpointer user)
175 {
176         switch (type) {
177         case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
178                 g_at_server_send_info(server, "oFono pre-1.0", TRUE);
179                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
180                 break;
181         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
182                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
183                 break;
184         default:
185                 g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
186         };
187 }
188
189 static void cgmr_cb(GAtServer *server, GAtServerRequestType type,
190                         GAtResult *cmd, gpointer user)
191 {
192         char buf[256];
193
194         switch (type) {
195         case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
196                 sprintf(buf, "oFono pre-1.0 version: %s", VERSION);
197                 g_at_server_send_info(server, buf, TRUE);
198                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
199                 break;
200         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
201                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
202                 break;
203         default:
204                 g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
205         };
206 }
207
208 static void cgsn_cb(GAtServer *server, GAtServerRequestType type,
209                         GAtResult *cmd, gpointer user)
210 {
211         switch (type) {
212         case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
213                 g_at_server_send_info(server, "123456789", TRUE);
214                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
215                 break;
216         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
217                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
218                 break;
219         default:
220                 g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
221         };
222 }
223
224 static gboolean send_ok(gpointer user)
225 {
226         GAtServer *server = user;
227
228         g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
229
230         return FALSE;
231 }
232
233 static void cfun_cb(GAtServer *server, GAtServerRequestType type,
234                         GAtResult *cmd, gpointer user)
235 {
236         char buf[12];
237
238         switch (type) {
239         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
240                 g_at_server_send_info(server, "+CFUN: (0-1,4)", TRUE);
241                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
242                 break;
243         case G_AT_SERVER_REQUEST_TYPE_QUERY:
244                 snprintf(buf, sizeof(buf), "+CFUN: %d", modem_mode);
245                 g_at_server_send_info(server, buf, TRUE);
246                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
247                 break;
248         case G_AT_SERVER_REQUEST_TYPE_SET:
249         {
250                 GAtResultIter iter;
251                 int mode;
252
253                 g_at_result_iter_init(&iter, cmd);
254                 g_at_result_iter_next(&iter, "");
255
256                 if (g_at_result_iter_next_number(&iter, &mode) == FALSE)
257                         goto error;
258
259                 if (mode != 0 && mode != 1)
260                         goto error;
261
262                 if (modem_mode == mode) {
263                         g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
264                         break;
265                 }
266
267                 modem_mode = mode;
268                 g_timeout_add_seconds(1, send_ok, server);
269                 break;
270         }
271         default:
272                 goto error;
273         };
274
275         return;
276
277 error:
278         g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
279 }
280
281 static void cusatt_cb(GAtServer *server, GAtServerRequestType type,
282                         GAtResult *cmd, gpointer user)
283 {
284         char buf[12];
285
286         switch (type) {
287         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
288                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
289                 break;
290         case G_AT_SERVER_REQUEST_TYPE_QUERY:
291                 g_at_server_send_ext_final(server, "+CME ERROR: 4");
292                 break;
293         case G_AT_SERVER_REQUEST_TYPE_SET:
294         {
295                 GAtResultIter iter;
296                 const unsigned char *pdu;
297                 int len;
298
299                 g_at_result_iter_init(&iter, cmd);
300                 g_at_result_iter_next(&iter, "");
301
302                 if (g_at_result_iter_next_hexstring(&iter, &pdu, &len) == FALSE)
303                         goto error;
304
305                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
306                 break;
307         }
308         default:
309                 goto error;
310         };
311
312         return;
313
314 error:
315         g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
316 }
317
318 static void listen_again(gpointer user_data)
319 {
320         if (create_tcp() == TRUE)
321                 return;
322
323         g_print("Error listening to socket\n");
324         g_main_loop_quit(main_loop);
325 }
326
327 static void setup_emulator(GAtServer *server)
328 {
329         g_at_server_set_debug(server, server_debug, "Server");
330
331         g_at_server_register(server, "+CGMI", cgmi_cb, NULL, NULL);
332         g_at_server_register(server, "+CGMM", cgmm_cb, NULL, NULL);
333         g_at_server_register(server, "+CGMR", cgmr_cb, NULL, NULL);
334         g_at_server_register(server, "+CGSN", cgsn_cb, NULL, NULL);
335         g_at_server_register(server, "+CFUN", cfun_cb, NULL, NULL);
336         g_at_server_register(server, "+CUSATT", cusatt_cb, NULL, NULL);
337
338         g_at_server_set_disconnect_function(server, listen_again, NULL);
339 }
340
341 static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
342                                                         gpointer user)
343 {
344         struct sockaddr saddr;
345         unsigned int len = sizeof(saddr);
346         int fd;
347         GIOChannel *client_io = NULL;
348
349         if (cond != G_IO_IN)
350                 goto error;
351
352         fd = accept(g_io_channel_unix_get_fd(chan), &saddr, &len);
353         if (fd == -1)
354                 goto error;
355
356         client_io = g_io_channel_unix_new(fd);
357
358         emulator = g_at_server_new(client_io);
359         g_at_server_set_echo(emulator, FALSE);
360         g_io_channel_unref(client_io);
361
362         if (emulator == NULL)
363                 goto error;
364
365         setup_emulator(emulator);
366
367 error:
368         server_watch = 0;
369         return FALSE;
370 }
371
372 static gboolean create_tcp(void)
373 {
374         struct sockaddr_in addr;
375         int sk;
376         int reuseaddr = 1;
377         GIOChannel *server_io;
378
379         sk = socket(PF_INET, SOCK_STREAM, 0);
380         if (sk < 0) {
381                 g_print("Can't create tcp/ip socket: %s (%d)\n",
382                                                 strerror(errno), errno);
383                 return FALSE;
384         }
385
386         memset(&addr, 0, sizeof(addr));
387
388         addr.sin_family = AF_INET;
389         addr.sin_addr.s_addr = INADDR_ANY;
390         addr.sin_port = htons(LISTEN_PORT);
391
392         setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
393         if (bind(sk, (struct sockaddr *) &addr, sizeof(struct sockaddr)) < 0) {
394                 g_print("Can't bind socket: %s (%d)", strerror(errno), errno);
395                 close(sk);
396                 return FALSE;
397         }
398
399         if (listen(sk, 1) < 0) {
400                 g_print("Can't listen on socket: %s (%d)",
401                                                 strerror(errno), errno);
402                 close(sk);
403                 return FALSE;
404         }
405
406         g_print("new tcp is created at tcp port %d\n", LISTEN_PORT);
407
408         server_io = g_io_channel_unix_new(sk);
409         g_io_channel_set_close_on_unref(server_io, TRUE);
410
411         server_watch = g_io_add_watch_full(server_io,
412                                 G_PRIORITY_DEFAULT,
413                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
414                                 on_socket_connected, NULL, NULL);
415
416         g_io_channel_unref(server_io);
417
418         return TRUE;
419 }
420
421 static gboolean has_stk_interface(DBusMessageIter *iter)
422 {
423         DBusMessageIter entry;
424
425         dbus_message_iter_recurse(iter, &entry);
426
427         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
428                 const char *interface;
429
430                 dbus_message_iter_get_basic(&entry, &interface);
431
432                 if (g_str_equal(interface, OFONO_STK_INTERFACE) == TRUE)
433                         return TRUE;
434
435                 dbus_message_iter_next(&entry);
436         }
437
438         return FALSE;
439 }
440
441 static int send_with_reply(const char *path, const char *interface,
442                                 const char *method, DBusPendingCall **call,
443                                 DBusPendingCallNotifyFunction cb,
444                                 void *user_data, DBusFreeFunction free_func,
445                                 int timeout, int type, ...)
446 {
447         DBusMessage *msg;
448         DBusPendingCall *c;
449         va_list args;
450         int err;
451
452         msg = dbus_message_new_method_call(OFONO_SERVICE, path,
453                                                 interface, method);
454         if (msg == NULL) {
455                 g_printerr("Unable to allocate new D-Bus %s message\n", method);
456                 err = -ENOMEM;
457                 goto fail;
458         }
459
460         va_start(args, type);
461
462         if (!dbus_message_append_args_valist(msg, type, args)) {
463                 va_end(args);
464                 err = -EIO;
465                 goto fail;
466         }
467
468         va_end(args);
469
470         if (timeout > 0)
471                 timeout *= 1000;
472
473         if (!dbus_connection_send_with_reply(conn, msg, &c, timeout)) {
474                 g_printerr("Sending %s failed\n", method);
475                 err = -EIO;
476                 goto fail;
477         }
478
479         if (call != NULL)
480                 *call = c;
481
482         dbus_pending_call_set_notify(c, cb, user_data, free_func);
483         dbus_pending_call_unref(c);
484
485         dbus_message_unref(msg);
486
487         return 0;
488
489 fail:
490         if (free_func && user_data)
491                 free_func(user_data);
492
493         if (msg)
494                 dbus_message_unref(msg);
495
496         return err;
497 }
498
499 static void set_property_reply(DBusPendingCall *call, void *user_data)
500 {
501         DBusMessage *reply = dbus_pending_call_steal_reply(call);
502         DBusError err;
503
504         dbus_error_init(&err);
505
506         if (dbus_set_error_from_message(&err, reply) == TRUE) {
507                 g_printerr("%s: %s\n", err.name, err.message);
508                 dbus_error_free(&err);
509         }
510
511         dbus_message_unref(reply);
512 }
513
514 static int set_property(const char *path, const char *interface,
515                         const char *key, int type, const void *val,
516                         DBusPendingCallNotifyFunction notify,
517                         gpointer user_data,
518                         DBusFreeFunction destroy)
519 {
520         DBusMessage *msg;
521         DBusMessageIter iter, value;
522         DBusPendingCall *call;
523         const char *signature;
524
525         msg = dbus_message_new_method_call(OFONO_SERVICE, path, interface,
526                                                 "SetProperty");
527         if (msg == NULL)
528                 return -ENOMEM;
529
530         dbus_message_set_auto_start(msg, FALSE);
531
532         dbus_message_iter_init_append(msg, &iter);
533
534         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
535
536         switch (type) {
537         case DBUS_TYPE_BOOLEAN:
538                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
539                 break;
540         default:
541                 dbus_message_unref(msg);
542                 return -EINVAL;
543         }
544
545         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
546                                                         signature, &value);
547         dbus_message_iter_append_basic(&value, type, val);
548         dbus_message_iter_close_container(&iter, &value);
549
550         if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
551                 dbus_message_unref(msg);
552                 return -EIO;
553         }
554
555         dbus_message_unref(msg);
556
557         if (call == NULL)
558                 return -EINVAL;
559
560         dbus_pending_call_set_notify(call, notify, user_data, destroy);
561
562         dbus_pending_call_unref(call);
563
564         return 0;
565 }
566
567 static void register_agent_reply(DBusPendingCall *call, void *user_data)
568 {
569         DBusMessage *reply = dbus_pending_call_steal_reply(call);
570         DBusError err;
571
572         dbus_error_init(&err);
573
574         if (dbus_set_error_from_message(&err, reply) == TRUE) {
575                 g_printerr("%s: %s\n", err.name, err.message);
576                 dbus_error_free(&err);
577         }
578
579         dbus_message_unref(reply);
580
581         state = TEST_STATE_RUNNING;
582 }
583
584 static void register_agent()
585 {
586         const char *path = "/default";
587         int status;
588
589         g_print("Gained STK interface, registering agent...\n");
590
591         status = send_with_reply(STKTEST_PATH, OFONO_STK_INTERFACE,
592                                         "RegisterAgent", NULL,
593                                         register_agent_reply, NULL, NULL, 1,
594                                         DBUS_TYPE_OBJECT_PATH, &path,
595                                         DBUS_TYPE_INVALID);
596
597         if (status < 0) {
598                 g_printerr("Unable to register agent with oFono\n");
599                 g_main_loop_quit(main_loop);
600                 return;
601         }
602
603         state = TEST_STATE_REGISTERING_AGENT;
604 }
605
606 static gboolean modem_changed(DBusConnection *conn,
607                                 DBusMessage *msg, void *user_data)
608 {
609         DBusMessageIter iter, value;
610         const char *path, *key;
611         gboolean has_stk;
612
613         if (dbus_message_iter_init(msg, &iter) == FALSE)
614                 return TRUE;
615
616         path = dbus_message_get_path(msg);
617
618         if (g_str_equal(STKTEST_PATH, path) == FALSE)
619                 return TRUE;
620
621         dbus_message_iter_get_basic(&iter, &key);
622
623         dbus_message_iter_next(&iter);
624         dbus_message_iter_recurse(&iter, &value);
625
626         if (g_str_equal(key, "Interfaces") == FALSE)
627                 return TRUE;
628
629         has_stk = has_stk_interface(&value);
630
631         switch (state) {
632         case TEST_STATE_POWERING_UP:
633                 if (has_stk)
634                         register_agent();
635                 break;
636         case TEST_STATE_REGISTERING_AGENT:
637         case TEST_STATE_RUNNING:
638                 if (has_stk == FALSE)
639                         g_printerr("Unexpectedly lost STK interface\n");
640                 /* Fall through */
641         case TEST_STATE_POWERING_DOWN:
642                 break;
643         };
644
645         return TRUE;
646 }
647
648 static void powerup(void)
649 {
650         dbus_bool_t powered = TRUE;
651
652         state = TEST_STATE_POWERING_UP;
653         set_property(STKTEST_PATH, OFONO_MODEM_INTERFACE, "Powered",
654                         DBUS_TYPE_BOOLEAN, &powered,
655                         set_property_reply, NULL, NULL);
656 }
657
658 static void get_modems_reply(DBusPendingCall *call, void *user_data)
659 {
660         DBusMessage *reply = dbus_pending_call_steal_reply(call);
661         DBusMessageIter iter, list;
662         DBusError err;
663         gboolean found = FALSE;
664
665         dbus_error_init(&err);
666
667         if (dbus_set_error_from_message(&err, reply) == TRUE) {
668                 g_printerr("%s: %s\n", err.name, err.message);
669                 dbus_error_free(&err);
670                 goto done;
671         }
672
673         if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
674                 goto done;
675
676         if (dbus_message_iter_init(reply, &iter) == FALSE)
677                 goto done;
678
679         dbus_message_iter_recurse(&iter, &list);
680
681         while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) {
682                 DBusMessageIter entry;
683                 const char *path;
684
685                 dbus_message_iter_recurse(&list, &entry);
686                 dbus_message_iter_get_basic(&entry, &path);
687
688                 if (g_str_equal(path, STKTEST_PATH))
689                         found = TRUE;
690
691                 dbus_message_iter_next(&list);
692         }
693
694 done:
695         dbus_message_unref(reply);
696
697         if (found == FALSE) {
698                 g_printerr("STK Test modem not found\n");
699                 g_main_loop_quit(main_loop);
700                 return;
701         }
702
703         g_print("Test modem found\n");
704
705         modem_changed_watch = g_dbus_add_signal_watch(conn, OFONO_SERVICE,
706                                                         STKTEST_PATH,
707                                                         OFONO_MODEM_INTERFACE,
708                                                         "PropertyChanged",
709                                                         modem_changed,
710                                                         NULL, NULL);
711
712         if (create_tcp() == FALSE) {
713                 g_printerr("Unable to listen on modem emulator socket\n");
714                 g_main_loop_quit(main_loop);
715         }
716
717         powerup();
718 }
719
720 static int get_modems(DBusConnection *conn)
721 {
722         DBusMessage *msg;
723         DBusPendingCall *call;
724
725         msg = dbus_message_new_method_call(OFONO_SERVICE, "/",
726                                         OFONO_MANAGER_INTERFACE, "GetModems");
727         if (msg == NULL)
728                 return -ENOMEM;
729
730         dbus_message_set_auto_start(msg, FALSE);
731
732         g_print("getting modems\n");
733
734         if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
735                 dbus_message_unref(msg);
736                 return -EIO;
737         }
738
739         dbus_message_unref(msg);
740
741         if (call == NULL)
742                 return -EINVAL;
743
744         dbus_pending_call_set_notify(call, get_modems_reply, conn, NULL);
745
746         dbus_pending_call_unref(call);
747
748         return 0;
749 }
750
751 static const GDBusMethodTable agent_methods[] = {
752         { GDBUS_METHOD("Release", NULL, NULL, agent_release) },
753         { GDBUS_METHOD("DisplayText",
754                 GDBUS_ARGS({ "text", "s" }, { "icon_id", "y" },
755                                 { "urgent", "b" }), NULL,
756                                 agent_display_text) },
757         { },
758 };
759
760 static void ofono_connect(DBusConnection *conn, void *user_data)
761 {
762         g_print("starting telephony interface\n");
763
764         if (!g_dbus_register_interface(conn, "/default",
765                                         OFONO_STKAGENT_INTERFACE,
766                                         agent_methods, NULL, NULL,
767                                         NULL, NULL)) {
768                 g_printerr("Unable to register local agent");
769                 g_main_loop_quit(main_loop);
770         }
771
772         ofono_running = TRUE;
773         get_modems(conn);
774 }
775
776 static void ofono_disconnect(DBusConnection *conn, void *user_data)
777 {
778         g_print("stopping telephony interface\n");
779
780         g_dbus_unregister_interface(conn, "/default", OFONO_STKAGENT_INTERFACE);
781
782         ofono_running = FALSE;
783
784         g_dbus_remove_watch(conn, modem_changed_watch);
785         modem_changed_watch = 0;
786
787         if (server_watch) {
788                 g_source_remove(server_watch);
789                 server_watch = 0;
790         }
791
792         g_at_server_unref(emulator);
793         emulator = NULL;
794 }
795
796 static void sig_term(int sig)
797 {
798         if (__terminated > 0)
799                 return;
800
801         __terminated = 1;
802
803         g_print("Terminating\n");
804
805         g_main_loop_quit(main_loop);
806 }
807
808 static void disconnect_callback(DBusConnection *conn, void *user_data)
809 {
810         g_printerr("D-Bus disconnect\n");
811
812         g_main_loop_quit(main_loop);
813 }
814
815 static gboolean option_version = FALSE;
816
817 static GOptionEntry options[] = {
818         { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
819                                 "Show version information and exit" },
820         { NULL },
821 };
822
823 int main(int argc, char **argv)
824 {
825         GOptionContext *context;
826         GError *error = NULL;
827         DBusError err;
828         guint watch;
829         struct sigaction sa;
830
831         context = g_option_context_new(NULL);
832         g_option_context_add_main_entries(context, options, NULL);
833
834         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
835                 if (error != NULL) {
836                         g_printerr("%s\n", error->message);
837                         g_error_free(error);
838                 } else
839                         g_printerr("An unknown error occurred\n");
840                 exit(1);
841         }
842
843         g_option_context_free(context);
844
845         if (option_version == TRUE) {
846                 printf("%s\n", VERSION);
847                 exit(0);
848         }
849
850         main_loop = g_main_loop_new(NULL, FALSE);
851
852         dbus_error_init(&err);
853
854         conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &err);
855         if (conn == NULL) {
856                 if (dbus_error_is_set(&err) == TRUE) {
857                         fprintf(stderr, "%s\n", err.message);
858                         dbus_error_free(&err);
859                 } else
860                         fprintf(stderr, "Can't register with system bus\n");
861                 exit(1);
862         }
863
864         g_dbus_set_disconnect_function(conn, disconnect_callback, NULL, NULL);
865
866         memset(&sa, 0, sizeof(sa));
867         sa.sa_handler = sig_term;
868         sigaction(SIGINT, &sa, NULL);
869         sigaction(SIGTERM, &sa, NULL);
870
871         watch = g_dbus_add_service_watch(conn, OFONO_SERVICE,
872                                 ofono_connect, ofono_disconnect, NULL, NULL);
873
874         g_main_loop_run(main_loop);
875
876         g_dbus_remove_watch(conn, watch);
877
878         if (ofono_running == TRUE)
879                 ofono_disconnect(conn, NULL);
880
881         dbus_connection_unref(conn);
882
883         g_main_loop_unref(main_loop);
884
885         return 0;
886 }