1//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17// Shim to set Cellular.APN property for a service. This exists because
18// dbus-send isn't capable of sending anything with nested containers, such as a
19// variant that is a dict.
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <dbus/dbus.h>
30
31#define CONNMAN_SERVICE			"org.chromium.flimflam"
32
33#define CONNMAN_SERVICE_INTERFACE	CONNMAN_SERVICE ".Service"
34
35static void append(DBusMessageIter *dict,
36		   const char *key,
37		   const char *value)
38{
39	DBusMessageIter entry;
40
41	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
42							NULL, &entry);
43
44	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
45
46	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
47
48	dbus_message_iter_close_container(dict, &entry);
49}
50
51int main(int argc, char *argv[])
52{
53	DBusConnection *conn;
54	DBusError error;
55	DBusMessage *msg;
56	DBusMessageIter iter, value, dict;
57	const char *property;
58	char *args;
59	char *cp;
60	char *argname;
61	char *argvalue;
62	int done;
63
64
65	if (argc < 4) {
66		fprintf(stderr,
67	"Usage: %s <service-dbus-path> <property-name> <apn-args>\n",
68			argv[0]);
69		return 1;
70	}
71
72	dbus_error_init(&error);
73
74	conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
75	if (conn == NULL) {
76		if (dbus_error_is_set(&error) == TRUE) {
77			fprintf(stderr, "%s\n", error.message);
78			dbus_error_free(&error);
79		} else
80			fprintf(stderr, "Failed to get on system bus\n");
81		return 1;
82	}
83
84	msg = dbus_message_new_method_call(CONNMAN_SERVICE,
85					   argv[1],
86					   CONNMAN_SERVICE_INTERFACE,
87					   "SetProperty");
88	if (msg == NULL) {
89		dbus_connection_unref(conn);
90		fprintf(stderr, "Failed to allocate method call\n");
91		return 1;
92	}
93
94	dbus_message_set_no_reply(msg, TRUE);
95
96	dbus_message_iter_init_append(msg, &iter);
97
98	property = argv[2];
99	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
100
101	dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
102			DBUS_TYPE_ARRAY_AS_STRING
103			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
104			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
105			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &value);
106
107	dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
108			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
109			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
110			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
111
112	args = argv[3];
113	cp = args;
114	done = 0;
115
116	while (!done) {
117		argname = cp;
118		cp = strchr(cp, ',');
119		if (cp == NULL) {
120			fprintf(stderr, "Badly formed argument string\n");
121			dbus_message_unref(msg);
122			dbus_connection_unref(conn);
123			return 1;
124		}
125		*cp++ = '\0';
126		argvalue = cp;
127		cp = strchr(cp, ',');
128		if (cp == NULL)
129			done = 1;
130		else
131			*cp++ = '\0';
132		append(&dict, argname, argvalue);
133	}
134
135	dbus_message_iter_close_container(&iter, &dict);
136	dbus_message_iter_close_container(&dict, &value);
137
138	dbus_connection_send(conn, msg, NULL);
139
140	dbus_message_unref(msg);
141	dbus_connection_unref(conn);
142
143	return 0;
144}
145