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