stktest: Further flesh out test framework
[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 enum test_result {
58         TEST_RESULT_NOT_RUN = 0,
59         TEST_RESULT_PASSED,
60         TEST_RESULT_FAILED
61 };
62
63 typedef DBusMessage *(*display_text_cb_t)(DBusMessage *msg, const char *text,
64                                                 unsigned char icon_id,
65                                                 gboolean urgent);
66 typedef void (*terminal_response_func)(const unsigned char *pdu,
67                                         unsigned int len);
68
69 struct test {
70         char *name;
71         char *method;
72         unsigned char *req_pdu;
73         unsigned int req_len;
74         unsigned char *rsp_pdu;
75         unsigned int rsp_len;
76         void *agent_func;
77         terminal_response_func tr_func;
78         enum test_result result;
79 };
80
81 static GMainLoop *main_loop = NULL;
82 static volatile sig_atomic_t __terminated = 0;
83 GList *tests = NULL;
84 GList *cur_test = NULL;
85
86 /* DBus related */
87 static DBusConnection *conn;
88 static gboolean ofono_running = FALSE;
89 static guint modem_changed_watch;
90 enum test_state state;
91
92 /* Emulator setup */
93 static guint server_watch;
94 static GAtServer *emulator;
95
96 /* Emulated modem state variables */
97 static int modem_mode = 0;
98
99 void __stktest_test_next();
100 void __stktest_test_finish(gboolean successful);
101 static gboolean create_tcp(void);
102
103 #define STKTEST_AGENT_ASSERT(expr)                                      \
104         do {                                                            \
105                 if (!(expr)) {                                          \
106                         g_printerr("Assertion Failed %s:%d %s\n",       \
107                                         __FILE__, __LINE__, #expr);     \
108                         __stktest_test_finish(FALSE);                   \
109                         return stktest_error_failed(msg);               \
110                 }                                                       \
111         } while (0)
112
113 #define STKTEST_RESPONSE_ASSERT(expect_pdu, expect_pdu_len,             \
114                                 got_pdu, got_pdu_len)                   \
115         do {                                                            \
116                 if ((expect_pdu_len) != (got_pdu_len)) {                \
117                         g_printerr("Assertion Failed %s:%d"             \
118                                         " Wrong response len"           \
119                                         " want: %d, got: %d\n",         \
120                                         __FILE__, __LINE__,             \
121                                         expect_pdu_len, got_pdu_len);   \
122                         __stktest_test_finish(FALSE);                   \
123                         return;                                         \
124                 }                                                       \
125                                                                         \
126                 if (memcmp(expect_pdu, got_pdu, expect_pdu_len) != 0) { \
127                         g_printerr("Assertion Failed %s:%d"             \
128                                         "Wrong response\n",             \
129                                         __FILE__, __LINE__);            \
130                         __stktest_test_finish(FALSE);                   \
131                         return;                                         \
132                 }                                                       \
133         } while (0)
134
135 static const char *to_hex(const unsigned char *data, unsigned int len)
136 {
137         static char buf[512+1];
138         unsigned int i;
139
140         for (i = 0; i < len; i++)
141                 sprintf(buf + i * 2, "%02hhX", data[i]);
142
143         buf[i*2] = '\0';
144
145         return buf;
146 }
147
148 static void send_proactive_command(const unsigned char *pdu, unsigned int len)
149 {
150         char buf[1024];
151
152         sprintf(buf, "+CUSATP: %s", to_hex(pdu, len));
153         g_at_server_send_unsolicited(emulator, buf);
154 }
155
156 static DBusMessage *stktest_error_invalid_args(DBusMessage *msg)
157 {
158         return g_dbus_create_error(msg, STKTEST_ERROR ".InvalidArguments",
159                                         "Invalid arguments provided");
160 }
161
162 static DBusMessage *stktest_error_failed(DBusMessage *msg)
163 {
164         return g_dbus_create_error(msg, STKTEST_ERROR ".Failed",
165                                         "Operation failed");
166 }
167
168 static DBusMessage *stktest_error_end_session(DBusMessage *msg)
169 {
170         return g_dbus_create_error(msg, OFONO_ERROR ".EndSession",
171                                         "End Session Request");
172 }
173
174 static DBusMessage *stktest_error_go_back(DBusMessage *msg)
175 {
176         return g_dbus_create_error(msg, OFONO_ERROR ".GoBack",
177                                         "Go Back Request");
178 }
179
180 static DBusMessage *stktest_error_busy(DBusMessage *msg)
181 {
182         return g_dbus_create_error(msg, OFONO_ERROR ".Busy",
183                                         "UI Busy");
184 }
185
186 static DBusMessage *agent_release(DBusConnection *conn, DBusMessage *msg,
187                                         void *data)
188 {
189         g_print("Got Release\n");
190
191         return dbus_message_new_method_return(msg);
192 }
193
194 static DBusMessage *agent_display_text(DBusConnection *conn, DBusMessage *msg,
195                                         void *data)
196 {
197         const char *text;
198         unsigned char icon_id;
199         dbus_bool_t urgent;
200         struct test *test;
201         display_text_cb_t func;
202
203         if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &text,
204                                                 DBUS_TYPE_BYTE, &icon_id,
205                                                 DBUS_TYPE_BOOLEAN, &urgent,
206                                                 DBUS_TYPE_INVALID) == FALSE)
207                 return stktest_error_invalid_args(msg);
208
209         if (cur_test == NULL)
210                 return stktest_error_failed(msg);
211
212         test = cur_test->data;
213         func = test->agent_func;
214
215         return func(msg, text, icon_id, urgent);
216 }
217
218 static void server_debug(const char *str, void *data)
219 {
220         g_print("%s: %s\n", (char *) data, str);
221 }
222
223 static void cgmi_cb(GAtServer *server, GAtServerRequestType type,
224                         GAtResult *cmd, gpointer user)
225 {
226         switch (type) {
227         case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
228                 g_at_server_send_info(server, "oFono", TRUE);
229                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
230                 break;
231         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
232                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
233                 break;
234         default:
235                 g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
236         };
237 }
238
239 static void cgmm_cb(GAtServer *server, GAtServerRequestType type,
240                         GAtResult *cmd, gpointer user)
241 {
242         switch (type) {
243         case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
244                 g_at_server_send_info(server, "oFono pre-1.0", TRUE);
245                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
246                 break;
247         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
248                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
249                 break;
250         default:
251                 g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
252         };
253 }
254
255 static void cgmr_cb(GAtServer *server, GAtServerRequestType type,
256                         GAtResult *cmd, gpointer user)
257 {
258         char buf[256];
259
260         switch (type) {
261         case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
262                 sprintf(buf, "oFono pre-1.0 version: %s", VERSION);
263                 g_at_server_send_info(server, buf, TRUE);
264                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
265                 break;
266         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
267                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
268                 break;
269         default:
270                 g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
271         };
272 }
273
274 static void cgsn_cb(GAtServer *server, GAtServerRequestType type,
275                         GAtResult *cmd, gpointer user)
276 {
277         switch (type) {
278         case G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY:
279                 g_at_server_send_info(server, "123456789", TRUE);
280                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
281                 break;
282         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
283                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
284                 break;
285         default:
286                 g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
287         };
288 }
289
290 static gboolean send_ok(gpointer user)
291 {
292         GAtServer *server = user;
293
294         g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
295
296         return FALSE;
297 }
298
299 static void cfun_cb(GAtServer *server, GAtServerRequestType type,
300                         GAtResult *cmd, gpointer user)
301 {
302         char buf[12];
303
304         switch (type) {
305         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
306                 g_at_server_send_info(server, "+CFUN: (0-1,4)", TRUE);
307                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
308                 break;
309         case G_AT_SERVER_REQUEST_TYPE_QUERY:
310                 snprintf(buf, sizeof(buf), "+CFUN: %d", modem_mode);
311                 g_at_server_send_info(server, buf, TRUE);
312                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
313                 break;
314         case G_AT_SERVER_REQUEST_TYPE_SET:
315         {
316                 GAtResultIter iter;
317                 int mode;
318
319                 g_at_result_iter_init(&iter, cmd);
320                 g_at_result_iter_next(&iter, "");
321
322                 if (g_at_result_iter_next_number(&iter, &mode) == FALSE)
323                         goto error;
324
325                 if (mode != 0 && mode != 1)
326                         goto error;
327
328                 if (modem_mode == mode) {
329                         g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
330                         break;
331                 }
332
333                 modem_mode = mode;
334                 g_timeout_add_seconds(1, send_ok, server);
335                 break;
336         }
337         default:
338                 goto error;
339         };
340
341         return;
342
343 error:
344         g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
345 }
346
347 static void cusatt_cb(GAtServer *server, GAtServerRequestType type,
348                         GAtResult *cmd, gpointer user)
349 {
350         switch (type) {
351         case G_AT_SERVER_REQUEST_TYPE_SUPPORT:
352                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
353                 break;
354         case G_AT_SERVER_REQUEST_TYPE_QUERY:
355                 g_at_server_send_ext_final(server, "+CME ERROR: 4");
356                 break;
357         case G_AT_SERVER_REQUEST_TYPE_SET:
358         {
359                 GAtResultIter iter;
360                 const unsigned char *pdu;
361                 int len;
362                 struct test *test;
363                 terminal_response_func func;
364
365                 g_at_result_iter_init(&iter, cmd);
366                 g_at_result_iter_next(&iter, "");
367
368                 if (g_at_result_iter_next_hexstring(&iter, &pdu, &len) == FALSE)
369                         goto error;
370
371                 if (cur_test == NULL)
372                         goto error;
373
374                 g_at_server_send_final(server, G_AT_SERVER_RESULT_OK);
375
376                 test = cur_test->data;
377                 func = test->tr_func;
378                 func(pdu, len);
379                 break;
380         }
381         default:
382                 goto error;
383         };
384
385         return;
386
387 error:
388         g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
389 }
390
391 static void listen_again(gpointer user_data)
392 {
393         g_at_server_unref(emulator);
394         emulator = NULL;
395
396         if (create_tcp() == TRUE)
397                 return;
398
399         g_print("Error listening to socket\n");
400         g_main_loop_quit(main_loop);
401 }
402
403 static void setup_emulator(GAtServer *server)
404 {
405         g_at_server_set_debug(server, server_debug, "Server");
406
407         g_at_server_register(server, "+CGMI", cgmi_cb, NULL, NULL);
408         g_at_server_register(server, "+CGMM", cgmm_cb, NULL, NULL);
409         g_at_server_register(server, "+CGMR", cgmr_cb, NULL, NULL);
410         g_at_server_register(server, "+CGSN", cgsn_cb, NULL, NULL);
411         g_at_server_register(server, "+CFUN", cfun_cb, NULL, NULL);
412         g_at_server_register(server, "+CUSATT", cusatt_cb, NULL, NULL);
413
414         g_at_server_set_disconnect_function(server, listen_again, NULL);
415 }
416
417 static gboolean on_socket_connected(GIOChannel *chan, GIOCondition cond,
418                                                         gpointer user)
419 {
420         struct sockaddr saddr;
421         unsigned int len = sizeof(saddr);
422         int fd;
423         GIOChannel *client_io = NULL;
424
425         if (cond != G_IO_IN)
426                 goto error;
427
428         fd = accept(g_io_channel_unix_get_fd(chan), &saddr, &len);
429         if (fd == -1)
430                 goto error;
431
432         client_io = g_io_channel_unix_new(fd);
433
434         emulator = g_at_server_new(client_io);
435         g_at_server_set_echo(emulator, FALSE);
436         g_io_channel_unref(client_io);
437
438         if (emulator == NULL)
439                 goto error;
440
441         setup_emulator(emulator);
442
443 error:
444         server_watch = 0;
445         return FALSE;
446 }
447
448 static gboolean create_tcp(void)
449 {
450         struct sockaddr_in addr;
451         int sk;
452         int reuseaddr = 1;
453         GIOChannel *server_io;
454
455         sk = socket(PF_INET, SOCK_STREAM, 0);
456         if (sk < 0) {
457                 g_print("Can't create tcp/ip socket: %s (%d)\n",
458                                                 strerror(errno), errno);
459                 return FALSE;
460         }
461
462         memset(&addr, 0, sizeof(addr));
463
464         addr.sin_family = AF_INET;
465         addr.sin_addr.s_addr = INADDR_ANY;
466         addr.sin_port = htons(LISTEN_PORT);
467
468         setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
469         if (bind(sk, (struct sockaddr *) &addr, sizeof(struct sockaddr)) < 0) {
470                 g_print("Can't bind socket: %s (%d)", strerror(errno), errno);
471                 close(sk);
472                 return FALSE;
473         }
474
475         if (listen(sk, 1) < 0) {
476                 g_print("Can't listen on socket: %s (%d)",
477                                                 strerror(errno), errno);
478                 close(sk);
479                 return FALSE;
480         }
481
482         g_print("new tcp is created at tcp port %d\n", LISTEN_PORT);
483
484         server_io = g_io_channel_unix_new(sk);
485         g_io_channel_set_close_on_unref(server_io, TRUE);
486
487         server_watch = g_io_add_watch_full(server_io,
488                                 G_PRIORITY_DEFAULT,
489                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
490                                 on_socket_connected, NULL, NULL);
491
492         g_io_channel_unref(server_io);
493
494         return TRUE;
495 }
496
497 static gboolean has_stk_interface(DBusMessageIter *iter)
498 {
499         DBusMessageIter entry;
500
501         dbus_message_iter_recurse(iter, &entry);
502
503         while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
504                 const char *interface;
505
506                 dbus_message_iter_get_basic(&entry, &interface);
507
508                 if (g_str_equal(interface, OFONO_STK_INTERFACE) == TRUE)
509                         return TRUE;
510
511                 dbus_message_iter_next(&entry);
512         }
513
514         return FALSE;
515 }
516
517 static int send_with_reply(const char *path, const char *interface,
518                                 const char *method, DBusPendingCall **call,
519                                 DBusPendingCallNotifyFunction cb,
520                                 void *user_data, DBusFreeFunction free_func,
521                                 int timeout, int type, ...)
522 {
523         DBusMessage *msg;
524         DBusPendingCall *c;
525         va_list args;
526         int err;
527
528         msg = dbus_message_new_method_call(OFONO_SERVICE, path,
529                                                 interface, method);
530         if (msg == NULL) {
531                 g_printerr("Unable to allocate new D-Bus %s message\n", method);
532                 err = -ENOMEM;
533                 goto fail;
534         }
535
536         va_start(args, type);
537
538         if (!dbus_message_append_args_valist(msg, type, args)) {
539                 va_end(args);
540                 err = -EIO;
541                 goto fail;
542         }
543
544         va_end(args);
545
546         if (timeout > 0)
547                 timeout *= 1000;
548
549         if (!dbus_connection_send_with_reply(conn, msg, &c, timeout)) {
550                 g_printerr("Sending %s failed\n", method);
551                 err = -EIO;
552                 goto fail;
553         }
554
555         if (call != NULL)
556                 *call = c;
557
558         dbus_pending_call_set_notify(c, cb, user_data, free_func);
559         dbus_pending_call_unref(c);
560
561         dbus_message_unref(msg);
562
563         return 0;
564
565 fail:
566         if (free_func && user_data)
567                 free_func(user_data);
568
569         if (msg)
570                 dbus_message_unref(msg);
571
572         return err;
573 }
574
575 static void set_property_reply(DBusPendingCall *call, void *user_data)
576 {
577         DBusMessage *reply = dbus_pending_call_steal_reply(call);
578         DBusError err;
579
580         dbus_error_init(&err);
581
582         if (dbus_set_error_from_message(&err, reply) == TRUE) {
583                 g_printerr("%s: %s\n", err.name, err.message);
584                 dbus_error_free(&err);
585         }
586
587         dbus_message_unref(reply);
588 }
589
590 static int set_property(const char *path, const char *interface,
591                         const char *key, int type, const void *val,
592                         DBusPendingCallNotifyFunction notify,
593                         gpointer user_data,
594                         DBusFreeFunction destroy)
595 {
596         DBusMessage *msg;
597         DBusMessageIter iter, value;
598         DBusPendingCall *call;
599         const char *signature;
600
601         msg = dbus_message_new_method_call(OFONO_SERVICE, path, interface,
602                                                 "SetProperty");
603         if (msg == NULL)
604                 return -ENOMEM;
605
606         dbus_message_set_auto_start(msg, FALSE);
607
608         dbus_message_iter_init_append(msg, &iter);
609
610         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
611
612         switch (type) {
613         case DBUS_TYPE_BOOLEAN:
614                 signature = DBUS_TYPE_BOOLEAN_AS_STRING;
615                 break;
616         default:
617                 dbus_message_unref(msg);
618                 return -EINVAL;
619         }
620
621         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
622                                                         signature, &value);
623         dbus_message_iter_append_basic(&value, type, val);
624         dbus_message_iter_close_container(&iter, &value);
625
626         if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
627                 dbus_message_unref(msg);
628                 return -EIO;
629         }
630
631         dbus_message_unref(msg);
632
633         if (call == NULL)
634                 return -EINVAL;
635
636         dbus_pending_call_set_notify(call, notify, user_data, destroy);
637
638         dbus_pending_call_unref(call);
639
640         return 0;
641 }
642
643 static void register_agent_reply(DBusPendingCall *call, void *user_data)
644 {
645         DBusMessage *reply = dbus_pending_call_steal_reply(call);
646         DBusError err;
647         struct test *test;
648
649         dbus_error_init(&err);
650
651         if (dbus_set_error_from_message(&err, reply) == TRUE) {
652                 g_printerr("%s: %s\n", err.name, err.message);
653                 dbus_error_free(&err);
654         }
655
656         dbus_message_unref(reply);
657
658         state = TEST_STATE_RUNNING;
659         test = cur_test->data;
660         send_proactive_command(test->req_pdu, test->req_len);
661 }
662
663 static void register_agent()
664 {
665         const char *path = "/default";
666         int status;
667
668         g_print("Gained STK interface, registering agent...\n");
669
670         status = send_with_reply(STKTEST_PATH, OFONO_STK_INTERFACE,
671                                         "RegisterAgent", NULL,
672                                         register_agent_reply, NULL, NULL, 1,
673                                         DBUS_TYPE_OBJECT_PATH, &path,
674                                         DBUS_TYPE_INVALID);
675
676         if (status < 0) {
677                 g_printerr("Unable to register agent with oFono\n");
678                 g_main_loop_quit(main_loop);
679                 return;
680         }
681
682         state = TEST_STATE_REGISTERING_AGENT;
683 }
684
685 static gboolean modem_changed(DBusConnection *conn,
686                                 DBusMessage *msg, void *user_data)
687 {
688         DBusMessageIter iter, value;
689         const char *path, *key;
690         gboolean has_stk;
691
692         if (dbus_message_iter_init(msg, &iter) == FALSE)
693                 return TRUE;
694
695         path = dbus_message_get_path(msg);
696
697         if (g_str_equal(STKTEST_PATH, path) == FALSE)
698                 return TRUE;
699
700         dbus_message_iter_get_basic(&iter, &key);
701
702         dbus_message_iter_next(&iter);
703         dbus_message_iter_recurse(&iter, &value);
704
705         if (g_str_equal(key, "Interfaces") == FALSE)
706                 return TRUE;
707
708         has_stk = has_stk_interface(&value);
709
710         switch (state) {
711         case TEST_STATE_POWERING_UP:
712                 if (has_stk)
713                         register_agent();
714                 break;
715         case TEST_STATE_REGISTERING_AGENT:
716         case TEST_STATE_RUNNING:
717                 if (has_stk == FALSE)
718                         g_printerr("Unexpectedly lost STK interface\n");
719                 /* Fall through */
720         case TEST_STATE_POWERING_DOWN:
721                 break;
722         };
723
724         return TRUE;
725 }
726
727 static void powerup(void)
728 {
729         dbus_bool_t powered = TRUE;
730
731         state = TEST_STATE_POWERING_UP;
732         set_property(STKTEST_PATH, OFONO_MODEM_INTERFACE, "Powered",
733                         DBUS_TYPE_BOOLEAN, &powered,
734                         set_property_reply, NULL, NULL);
735 }
736
737 static void get_modems_reply(DBusPendingCall *call, void *user_data)
738 {
739         DBusMessage *reply = dbus_pending_call_steal_reply(call);
740         DBusMessageIter iter, list;
741         DBusError err;
742         gboolean found = FALSE;
743
744         dbus_error_init(&err);
745
746         if (dbus_set_error_from_message(&err, reply) == TRUE) {
747                 g_printerr("%s: %s\n", err.name, err.message);
748                 dbus_error_free(&err);
749                 goto done;
750         }
751
752         if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE)
753                 goto done;
754
755         if (dbus_message_iter_init(reply, &iter) == FALSE)
756                 goto done;
757
758         dbus_message_iter_recurse(&iter, &list);
759
760         while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) {
761                 DBusMessageIter entry;
762                 const char *path;
763
764                 dbus_message_iter_recurse(&list, &entry);
765                 dbus_message_iter_get_basic(&entry, &path);
766
767                 if (g_str_equal(path, STKTEST_PATH))
768                         found = TRUE;
769
770                 dbus_message_iter_next(&list);
771         }
772
773 done:
774         dbus_message_unref(reply);
775
776         if (found == FALSE) {
777                 g_printerr("STK Test modem not found\n");
778                 g_main_loop_quit(main_loop);
779                 return;
780         }
781
782         g_print("Test modem found\n");
783
784         modem_changed_watch = g_dbus_add_signal_watch(conn, OFONO_SERVICE,
785                                                         STKTEST_PATH,
786                                                         OFONO_MODEM_INTERFACE,
787                                                         "PropertyChanged",
788                                                         modem_changed,
789                                                         NULL, NULL);
790
791         if (create_tcp() == FALSE) {
792                 g_printerr("Unable to listen on modem emulator socket\n");
793                 g_main_loop_quit(main_loop);
794         }
795
796         __stktest_test_next();
797 }
798
799 static int get_modems(DBusConnection *conn)
800 {
801         DBusMessage *msg;
802         DBusPendingCall *call;
803
804         msg = dbus_message_new_method_call(OFONO_SERVICE, "/",
805                                         OFONO_MANAGER_INTERFACE, "GetModems");
806         if (msg == NULL)
807                 return -ENOMEM;
808
809         dbus_message_set_auto_start(msg, FALSE);
810
811         g_print("getting modems\n");
812
813         if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) {
814                 dbus_message_unref(msg);
815                 return -EIO;
816         }
817
818         dbus_message_unref(msg);
819
820         if (call == NULL)
821                 return -EINVAL;
822
823         dbus_pending_call_set_notify(call, get_modems_reply, conn, NULL);
824
825         dbus_pending_call_unref(call);
826
827         return 0;
828 }
829
830 static const GDBusMethodTable agent_methods[] = {
831         { GDBUS_METHOD("Release", NULL, NULL, agent_release) },
832         { GDBUS_METHOD("DisplayText",
833                 GDBUS_ARGS({ "text", "s" }, { "icon_id", "y" },
834                                 { "urgent", "b" }), NULL,
835                                 agent_display_text) },
836         { },
837 };
838
839 static void ofono_connect(DBusConnection *conn, void *user_data)
840 {
841         g_print("starting telephony interface\n");
842
843         if (!g_dbus_register_interface(conn, "/default",
844                                         OFONO_STKAGENT_INTERFACE,
845                                         agent_methods, NULL, NULL,
846                                         NULL, NULL)) {
847                 g_printerr("Unable to register local agent");
848                 g_main_loop_quit(main_loop);
849         }
850
851         ofono_running = TRUE;
852         get_modems(conn);
853 }
854
855 static void ofono_disconnect(DBusConnection *conn, void *user_data)
856 {
857         g_print("stopping telephony interface\n");
858
859         g_dbus_unregister_interface(conn, "/default", OFONO_STKAGENT_INTERFACE);
860
861         ofono_running = FALSE;
862
863         g_dbus_remove_watch(conn, modem_changed_watch);
864         modem_changed_watch = 0;
865
866         if (server_watch) {
867                 g_source_remove(server_watch);
868                 server_watch = 0;
869         }
870
871         g_at_server_unref(emulator);
872         emulator = NULL;
873 }
874
875 static void sig_term(int sig)
876 {
877         if (__terminated > 0)
878                 return;
879
880         __terminated = 1;
881
882         g_print("Terminating\n");
883
884         g_main_loop_quit(main_loop);
885 }
886
887 static void disconnect_callback(DBusConnection *conn, void *user_data)
888 {
889         g_printerr("D-Bus disconnect\n");
890
891         g_main_loop_quit(main_loop);
892 }
893
894 static void power_down_reply(DBusPendingCall *call, void *user_data)
895 {
896         __stktest_test_next();
897 }
898
899 void __stktest_test_finish(gboolean successful)
900 {
901         struct test *test = cur_test->data;
902         dbus_bool_t powered = FALSE;
903
904         test->result = successful ? TEST_RESULT_PASSED : TEST_RESULT_FAILED;
905
906         state = TEST_STATE_POWERING_DOWN;
907         set_property(STKTEST_PATH, OFONO_MODEM_INTERFACE, "Powered",
908                         DBUS_TYPE_BOOLEAN, &powered,
909                         power_down_reply, NULL, NULL);
910 }
911
912 void __stktest_test_next()
913 {
914         if (cur_test == NULL)
915                 cur_test = tests;
916         else
917                 cur_test = cur_test->next;
918
919         if (cur_test == NULL)
920                 g_main_loop_quit(main_loop);
921
922         powerup();
923 }
924
925 static void stktest_add_test(const char *name, const char *method,
926                                 const unsigned char *req, unsigned int req_len,
927                                 const unsigned char *rsp, unsigned int rsp_len,
928                                 void *agent_func,
929                                 terminal_response_func tr_func)
930 {
931         struct test *test = g_new0(struct test, 1);
932
933         test->name = g_strdup(name);
934         test->method = g_strdup(method);
935         test->req_pdu = g_memdup(req, req_len);
936         test->req_len = req_len;
937         test->rsp_pdu = g_memdup(rsp, rsp_len);
938         test->rsp_len = rsp_len;
939         test->agent_func = agent_func;
940         test->tr_func = tr_func;
941
942         tests = g_list_append(tests, test);
943 }
944
945 static void __stktest_test_init(void)
946 {
947 }
948
949 static void test_destroy(gpointer user_data)
950 {
951         struct test *test = user_data;
952
953         g_free(test->name);
954         g_free(test->method);
955         g_free(test->req_pdu);
956         g_free(test->rsp_pdu);
957
958         g_free(test);
959 }
960
961 static void __stktest_test_summarize(void)
962 {
963         GList *l;
964
965         g_print("\n\nTest Summary\n");
966         g_print("============\n");
967
968         for (l = tests; l; l = l->next) {
969                 struct test *test = l->data;
970
971                 g_print("%-60s", test->name);
972
973                 switch (test->result) {
974                 case TEST_RESULT_NOT_RUN:
975                         g_print("Not Run\n");
976                         break;
977                 case TEST_RESULT_PASSED:
978                         g_print("Passed\n");
979                         break;
980                 case TEST_RESULT_FAILED:
981                         g_print("Failed\n");
982                 break;
983                 }
984         }
985 }
986
987 static void __stktest_test_cleanup(void)
988 {
989         g_list_free_full(tests, test_destroy);
990         tests = NULL;
991         cur_test = NULL;
992 }
993
994 static gboolean option_version = FALSE;
995
996 static GOptionEntry options[] = {
997         { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
998                                 "Show version information and exit" },
999         { NULL },
1000 };
1001
1002 int main(int argc, char **argv)
1003 {
1004         GOptionContext *context;
1005         GError *error = NULL;
1006         DBusError err;
1007         guint watch;
1008         struct sigaction sa;
1009
1010         context = g_option_context_new(NULL);
1011         g_option_context_add_main_entries(context, options, NULL);
1012
1013         if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
1014                 if (error != NULL) {
1015                         g_printerr("%s\n", error->message);
1016                         g_error_free(error);
1017                 } else
1018                         g_printerr("An unknown error occurred\n");
1019                 exit(1);
1020         }
1021
1022         g_option_context_free(context);
1023
1024         if (option_version == TRUE) {
1025                 printf("%s\n", VERSION);
1026                 exit(0);
1027         }
1028
1029         __stktest_test_init();
1030
1031         main_loop = g_main_loop_new(NULL, FALSE);
1032
1033         dbus_error_init(&err);
1034
1035         conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &err);
1036         if (conn == NULL) {
1037                 if (dbus_error_is_set(&err) == TRUE) {
1038                         fprintf(stderr, "%s\n", err.message);
1039                         dbus_error_free(&err);
1040                 } else
1041                         fprintf(stderr, "Can't register with system bus\n");
1042                 exit(1);
1043         }
1044
1045         g_dbus_set_disconnect_function(conn, disconnect_callback, NULL, NULL);
1046
1047         memset(&sa, 0, sizeof(sa));
1048         sa.sa_handler = sig_term;
1049         sigaction(SIGINT, &sa, NULL);
1050         sigaction(SIGTERM, &sa, NULL);
1051
1052         watch = g_dbus_add_service_watch(conn, OFONO_SERVICE,
1053                                 ofono_connect, ofono_disconnect, NULL, NULL);
1054
1055         g_main_loop_run(main_loop);
1056
1057         g_dbus_remove_watch(conn, watch);
1058
1059         if (ofono_running == TRUE)
1060                 ofono_disconnect(conn, NULL);
1061
1062         dbus_connection_unref(conn);
1063
1064         g_main_loop_unref(main_loop);
1065
1066         __stktest_test_summarize();
1067         __stktest_test_cleanup();
1068
1069         return 0;
1070 }