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