stktest: merge cusatt
[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         switch (type) {
285         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
286                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
287                 break;
288         case G_AT_SERVER_REQUEST_TYPE_QUERY:
289                 g_at_server_send_ext_final(server, "+CME ERROR: 4");
290                 break;
291         case G_AT_SERVER_REQUEST_TYPE_SET:
292         {
293                 GAtResultIter iter;
294                 const unsigned char *pdu;
295                 int len;
296
297                 g_at_result_iter_init(&iter, cmd);
298                 g_at_result_iter_next(&iter, "");
299
300                 if (g_at_result_iter_next_hexstring(&iter, &pdu, &len) == FALSE)
301                         goto error;
302
303                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
304                 break;
305         }
306         default:
307                 goto error;
308         };
309
310         return;
311
312 error:
313         g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
314 }
315
316 static void listen_again(gpointer user_data)
317 {
318         if (create_tcp() == TRUE)
319                 return;
320
321         g_print("Error listening to socket\n");
322         g_main_loop_quit(main_loop);
323 }
324
325 static void setup_emulator(GAtServer *server)
326 {
327         g_at_server_set_debug(server, server_debug, "Server");
328
329         g_at_server_register(server, "+CGMI", cgmi_cb, NULL, NULL);
330         g_at_server_register(server, "+CGMM", cgmm_cb, NULL, NULL);
331         g_at_server_register(server, "+CGMR", cgmr_cb, NULL, NULL);
332         g_at_server_register(server, "+CGSN", cgsn_cb, NULL, NULL);
333         g_at_server_register(server, "+CFUN", cfun_cb, NULL, NULL);
334         g_at_server_register(server, "+CUSATT", cusatt_cb, NULL, NULL);
335
336         g_at_server_set_disconnect_function(server, listen_again, NULL);
337 }
338
339 static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
340                                                         gpointer user)
341 {
342         struct sockaddr saddr;
343         unsigned int len = sizeof(saddr);
344         int fd;
345         GIOChannel *client_io = NULL;
346
347         if (cond != G_IO_IN)
348                 goto error;
349
350         fd = accept(g_io_channel_unix_get_fd(chan), &saddr, &len);
351         if (fd == -1)
352                 goto error;
353
354         client_io = g_io_channel_unix_new(fd);
355
356         emulator = g_at_server_new(client_io);
357         g_at_server_set_echo(emulator, FALSE);
358         g_io_channel_unref(client_io);
359
360         if (emulator == NULL)
361                 goto error;
362
363         setup_emulator(emulator);
364
365 error:
366         server_watch = 0;
367         return FALSE;
368 }
369
370 static gboolean create_tcp(void)
371 {
372         struct sockaddr_in addr;
373         int sk;
374         int reuseaddr = 1;
375         GIOChannel *server_io;
376
377         sk = socket(PF_INET, SOCK_STREAM, 0);
378         if (sk < 0) {
379                 g_print("Can't create tcp/ip socket: %s (%d)\n",
380                                                 strerror(errno), errno);
381                 return FALSE;
382         }
383
384         memset(&addr, 0, sizeof(addr));
385
386         addr.sin_family = AF_INET;
387         addr.sin_addr.s_addr = INADDR_ANY;
388         addr.sin_port = htons(LISTEN_PORT);
389
390         setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
391         if (bind(sk, (struct sockaddr *) &addr, sizeof(struct sockaddr)) < 0) {
392                 g_print("Can't bind socket: %s (%d)", strerror(errno), errno);
393                 close(sk);
394                 return FALSE;
395         }
396
397         if (listen(sk, 1) < 0) {
398                 g_print("Can't listen on socket: %s (%d)",
399                                                 strerror(errno), errno);
400                 close(sk);
401                 return FALSE;
402         }
403
404         g_print("new tcp is created at tcp port %d\n", LISTEN_PORT);
405
406         server_io = g_io_channel_unix_new(sk);
407         g_io_channel_set_close_on_unref(server_io, TRUE);
408
409         server_watch = g_io_add_watch_full(server_io,
410                                 G_PRIORITY_DEFAULT,
411                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
412                                 on_socket_connected, NULL, NULL);
413
414         g_io_channel_unref(server_io);
415
416         return TRUE;
417 }
418
419 static gboolean has_stk_interface(DBusMessageIter *iter)
420 {
421         DBusMessageIter entry;
422
423         dbus_message_iter_recurse(iter, &entry);
424
425         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
426                 const char *interface;
427
428                 dbus_message_iter_get_basic(&entry, &interface);
429
430                 if (g_str_equal(interface, OFONO_STK_INTERFACE) == TRUE)
431                         return TRUE;
432
433                 dbus_message_iter_next(&entry);
434         }
435
436         return FALSE;
437 }
438
439 static int send_with_reply(const char *path, const char *interface,
440                                 const char *method, DBusPendingCall **call,
441                                 DBusPendingCallNotifyFunction cb,
442                                 void *user_data, DBusFreeFunction free_func,
443                                 int timeout, int type, ...)
444 {
445         DBusMessage *msg;
446         DBusPendingCall *c;
447         va_list args;
448         int err;
449
450         msg = dbus_message_new_method_call(OFONO_SERVICE, path,
451                                                 interface, method);
452         if (msg == NULL) {
453                 g_printerr("Unable to allocate new D-Bus %s message\n", method);
454                 err = -ENOMEM;
455                 goto fail;
456         }
457
458         va_start(args, type);
459
460         if (!dbus_message_append_args_valist(msg, type, args)) {
461                 va_end(args);
462                 err = -EIO;
463                 goto fail;
464         }
465
466         va_end(args);
467
468         if (timeout > 0)
469                 timeout *= 1000;
470
471         if (!dbus_connection_send_with_reply(conn, msg, &c, timeout)) {
472                 g_printerr("Sending %s failed\n", method);
473                 err = -EIO;
474                 goto fail;
475         }
476
477         if (call != NULL)
478                 *call = c;
479
480         dbus_pending_call_set_notify(c, cb, user_data, free_func);
481         dbus_pending_call_unref(c);
482
483         dbus_message_unref(msg);
484
485         return 0;
486
487 fail:
488         if (free_func && user_data)
489                 free_func(user_data);
490
491         if (msg)
492                 dbus_message_unref(msg);
493
494         return err;
495 }
496
497 static void set_property_reply(DBusPendingCall *call, void *user_data)
498 {
499         DBusMessage *reply = dbus_pending_call_steal_reply(call);
500         DBusError err;
501
502         dbus_error_init(&err);
503
504         if (dbus_set_error_from_message(&err, reply) == TRUE) {
505                 g_printerr("%s: %s\n", err.name, err.message);
506                 dbus_error_free(&err);
507         }
508
509         dbus_message_unref(reply);
510 }
511
512 static int set_property(const char *path, const char *interface,
513                         const char *key, int type, const void *val,
514                         DBusPendingCallNotifyFunction notify,
515                         gpointer user_data,
516                         DBusFreeFunction destroy)
517 {
518         DBusMessage *msg;
519         DBusMessageIter iter, value;
520         DBusPendingCall *call;
521         const char *signature;
522
523         msg = dbus_message_new_method_call(OFONO_SERVICE, path, interface,
524                                                 "SetProperty");
525         if (msg == NULL)
526                 return -ENOMEM;
527
528         dbus_message_set_auto_start(msg, FALSE);
529
530         dbus_message_iter_init_append(msg, &iter);
531
532         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
533
534         switch (type) {
535         case DBUS_TYPE_BOOLEAN:
536                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
537                 break;
538         default:
539                 dbus_message_unref(msg);
540                 return -EINVAL;
541         }
542
543         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
544                                                         signature, &value);
545         dbus_message_iter_append_basic(&value, type, val);
546         dbus_message_iter_close_container(&iter, &value);
547
548         if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
549                 dbus_message_unref(msg);
550                 return -EIO;
551         }
552
553         dbus_message_unref(msg);
554
555         if (call == NULL)
556                 return -EINVAL;
557
558         dbus_pending_call_set_notify(call, notify, user_data, destroy);
559
560         dbus_pending_call_unref(call);
561
562         return 0;
563 }
564
565 static void register_agent_reply(DBusPendingCall *call, void *user_data)
566 {
567         DBusMessage *reply = dbus_pending_call_steal_reply(call);
568         DBusError err;
569
570         dbus_error_init(&err);
571
572         if (dbus_set_error_from_message(&err, reply) == TRUE) {
573                 g_printerr("%s: %s\n", err.name, err.message);
574                 dbus_error_free(&err);
575         }
576
577         dbus_message_unref(reply);
578
579         state = TEST_STATE_RUNNING;
580 }
581
582 static void register_agent()
583 {
584         const char *path = "/default";
585         int status;
586
587         g_print("Gained STK interface, registering agent...\n");
588
589         status = send_with_reply(STKTEST_PATH, OFONO_STK_INTERFACE,
590                                         "RegisterAgent", NULL,
591                                         register_agent_reply, NULL, NULL, 1,
592                                         DBUS_TYPE_OBJECT_PATH, &path,
593                                         DBUS_TYPE_INVALID);
594
595         if (status < 0) {
596                 g_printerr("Unable to register agent with oFono\n");
597                 g_main_loop_quit(main_loop);
598                 return;
599         }
600
601         state = TEST_STATE_REGISTERING_AGENT;
602 }
603
604 static gboolean modem_changed(DBusConnection *conn,
605                                 DBusMessage *msg, void *user_data)
606 {
607         DBusMessageIter iter, value;
608         const char *path, *key;
609         gboolean has_stk;
610
611         if (dbus_message_iter_init(msg, &iter) == FALSE)
612                 return TRUE;
613
614         path = dbus_message_get_path(msg);
615
616         if (g_str_equal(STKTEST_PATH, path) == FALSE)
617                 return TRUE;
618
619         dbus_message_iter_get_basic(&iter, &key);
620
621         dbus_message_iter_next(&iter);
622         dbus_message_iter_recurse(&iter, &value);
623
624         if (g_str_equal(key, "Interfaces") == FALSE)
625                 return TRUE;
626
627         has_stk = has_stk_interface(&value);
628
629         switch (state) {
630         case TEST_STATE_POWERING_UP:
631                 if (has_stk)
632                         register_agent();
633                 break;
634         case TEST_STATE_REGISTERING_AGENT:
635         case TEST_STATE_RUNNING:
636                 if (has_stk == FALSE)
637                         g_printerr("Unexpectedly lost STK interface\n");
638                 /* Fall through */
639         case TEST_STATE_POWERING_DOWN:
640                 break;
641         };
642
643         return TRUE;
644 }
645
646 static void powerup(void)
647 {
648         dbus_bool_t powered = TRUE;
649
650         state = TEST_STATE_POWERING_UP;
651         set_property(STKTEST_PATH, OFONO_MODEM_INTERFACE, "Powered",
652                         DBUS_TYPE_BOOLEAN, &powered,
653                         set_property_reply, NULL, NULL);
654 }
655
656 static void get_modems_reply(DBusPendingCall *call, void *user_data)
657 {
658         DBusMessage *reply = dbus_pending_call_steal_reply(call);
659         DBusMessageIter iter, list;
660         DBusError err;
661         gboolean found = FALSE;
662
663         dbus_error_init(&err);
664
665         if (dbus_set_error_from_message(&err, reply) == TRUE) {
666                 g_printerr("%s: %s\n", err.name, err.message);
667                 dbus_error_free(&err);
668                 goto done;
669         }
670
671         if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
672                 goto done;
673
674         if (dbus_message_iter_init(reply, &iter) == FALSE)
675                 goto done;
676
677         dbus_message_iter_recurse(&iter, &list);
678
679         while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) {
680                 DBusMessageIter entry;
681                 const char *path;
682
683                 dbus_message_iter_recurse(&list, &entry);
684                 dbus_message_iter_get_basic(&entry, &path);
685
686                 if (g_str_equal(path, STKTEST_PATH))
687                         found = TRUE;
688
689                 dbus_message_iter_next(&list);
690         }
691
692 done:
693         dbus_message_unref(reply);
694
695         if (found == FALSE) {
696                 g_printerr("STK Test modem not found\n");
697                 g_main_loop_quit(main_loop);
698                 return;
699         }
700
701         g_print("Test modem found\n");
702
703         modem_changed_watch = g_dbus_add_signal_watch(conn, OFONO_SERVICE,
704                                                         STKTEST_PATH,
705                                                         OFONO_MODEM_INTERFACE,
706                                                         "PropertyChanged",
707                                                         modem_changed,
708                                                         NULL, NULL);
709
710         if (create_tcp() == FALSE) {
711                 g_printerr("Unable to listen on modem emulator socket\n");
712                 g_main_loop_quit(main_loop);
713         }
714
715         powerup();
716 }
717
718 static int get_modems(DBusConnection *conn)
719 {
720         DBusMessage *msg;
721         DBusPendingCall *call;
722
723         msg = dbus_message_new_method_call(OFONO_SERVICE, "/",
724                                         OFONO_MANAGER_INTERFACE, "GetModems");
725         if (msg == NULL)
726                 return -ENOMEM;
727
728         dbus_message_set_auto_start(msg, FALSE);
729
730         g_print("getting modems\n");
731
732         if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
733                 dbus_message_unref(msg);
734                 return -EIO;
735         }
736
737         dbus_message_unref(msg);
738
739         if (call == NULL)
740                 return -EINVAL;
741
742         dbus_pending_call_set_notify(call, get_modems_reply, conn, NULL);
743
744         dbus_pending_call_unref(call);
745
746         return 0;
747 }
748
749 static const GDBusMethodTable agent_methods[] = {
750         { GDBUS_METHOD("Release", NULL, NULL, agent_release) },
751         { GDBUS_METHOD("DisplayText",
752                 GDBUS_ARGS({ "text", "s" }, { "icon_id", "y" },
753                                 { "urgent", "b" }), NULL,
754                                 agent_display_text) },
755         { },
756 };
757
758 static void ofono_connect(DBusConnection *conn, void *user_data)
759 {
760         g_print("starting telephony interface\n");
761
762         if (!g_dbus_register_interface(conn, "/default",
763                                         OFONO_STKAGENT_INTERFACE,
764                                         agent_methods, NULL, NULL,
765                                         NULL, NULL)) {
766                 g_printerr("Unable to register local agent");
767                 g_main_loop_quit(main_loop);
768         }
769
770         ofono_running = TRUE;
771         get_modems(conn);
772 }
773
774 static void ofono_disconnect(DBusConnection *conn, void *user_data)
775 {
776         g_print("stopping telephony interface\n");
777
778         g_dbus_unregister_interface(conn, "/default", OFONO_STKAGENT_INTERFACE);
779
780         ofono_running = FALSE;
781
782         g_dbus_remove_watch(conn, modem_changed_watch);
783         modem_changed_watch = 0;
784
785         if (server_watch) {
786                 g_source_remove(server_watch);
787                 server_watch = 0;
788         }
789
790         g_at_server_unref(emulator);
791         emulator = NULL;
792 }
793
794 static void sig_term(int sig)
795 {
796         if (__terminated > 0)
797                 return;
798
799         __terminated = 1;
800
801         g_print("Terminating\n");
802
803         g_main_loop_quit(main_loop);
804 }
805
806 static void disconnect_callback(DBusConnection *conn, void *user_data)
807 {
808         g_printerr("D-Bus disconnect\n");
809
810         g_main_loop_quit(main_loop);
811 }
812
813 static gboolean option_version = FALSE;
814
815 static GOptionEntry options[] = {
816         { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
817                                 "Show version information and exit" },
818         { NULL },
819 };
820
821 int main(int argc, char **argv)
822 {
823         GOptionContext *context;
824         GError *error = NULL;
825         DBusError err;
826         guint watch;
827         struct sigaction sa;
828
829         context = g_option_context_new(NULL);
830         g_option_context_add_main_entries(context, options, NULL);
831
832         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
833                 if (error != NULL) {
834                         g_printerr("%s\n", error->message);
835                         g_error_free(error);
836                 } else
837                         g_printerr("An unknown error occurred\n");
838                 exit(1);
839         }
840
841         g_option_context_free(context);
842
843         if (option_version == TRUE) {
844                 printf("%s\n", VERSION);
845                 exit(0);
846         }
847
848         main_loop = g_main_loop_new(NULL, FALSE);
849
850         dbus_error_init(&err);
851
852         conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &err);
853         if (conn == NULL) {
854                 if (dbus_error_is_set(&err) == TRUE) {
855                         fprintf(stderr, "%s\n", err.message);
856                         dbus_error_free(&err);
857                 } else
858                         fprintf(stderr, "Can't register with system bus\n");
859                 exit(1);
860         }
861
862         g_dbus_set_disconnect_function(conn, disconnect_callback, NULL, NULL);
863
864         memset(&sa, 0, sizeof(sa));
865         sa.sa_handler = sig_term;
866         sigaction(SIGINT, &sa, NULL);
867         sigaction(SIGTERM, &sa, NULL);
868
869         watch = g_dbus_add_service_watch(conn, OFONO_SERVICE,
870                                 ofono_connect, ofono_disconnect, NULL, NULL);
871
872         g_main_loop_run(main_loop);
873
874         g_dbus_remove_watch(conn, watch);
875
876         if (ofono_running == TRUE)
877                 ofono_disconnect(conn, NULL);
878
879         dbus_connection_unref(conn);
880
881         g_main_loop_unref(main_loop);
882
883         return 0;
884 }