• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <glib.h>
7 #include <ibus.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string>
11 
12 namespace {
13 
14 const gchar kDummySection[] = "aaa/bbb";
15 const gchar kDummyConfigName[] = "ccc";
16 
17 const gboolean kDummyValueBoolean = TRUE;
18 const gint kDummyValueInt = 12345;
19 const gdouble kDummyValueDouble = 2345.5432;
20 const gchar kDummyValueString[] = "dummy value";
21 
22 const size_t kArraySize = 3;
23 const gboolean kDummyValueBooleanArray[kArraySize] = { FALSE, TRUE, FALSE };
24 const gint kDummyValueIntArray[kArraySize] = { 123, 234, 345 };
25 const gdouble kDummyValueDoubleArray[kArraySize] = { 111.22, 333.44, 555.66 };
26 const gchar* kDummyValueStringArray[kArraySize] = {
27   "DUMMY_VALUE 1", "DUMMY_VALUE 2", "DUMMY_VALUE 3",
28 };
29 
30 const char kGeneralSectionName[] = "general";
31 const char kPreloadEnginesConfigName[] = "preload_engines";
32 
33 // Converts |list_type_string| into its element type (e.g. "int_list" to "int").
GetElementType(const std::string & list_type_string)34 std::string GetElementType(const std::string& list_type_string) {
35   const std::string suffix = "_list";
36   if (list_type_string.length() > suffix.length()) {
37     return list_type_string.substr(
38         0, list_type_string.length() - suffix.length());
39   }
40   return list_type_string;
41 }
42 
43 // Converts |type_string| into GVariantClass.
GetGVariantClassFromStringOrDie(const std::string & type_string)44 GVariantClass GetGVariantClassFromStringOrDie(const std::string& type_string) {
45   if (type_string == "boolean") {
46     return G_VARIANT_CLASS_BOOLEAN;
47   } else if (type_string == "int") {
48     return G_VARIANT_CLASS_INT32;
49   } else if (type_string == "double") {
50     return G_VARIANT_CLASS_DOUBLE;
51   } else if (type_string == "string") {
52     return G_VARIANT_CLASS_STRING;
53   } else if (GetElementType(type_string) != type_string) {
54     return G_VARIANT_CLASS_ARRAY;
55   }
56   printf("FAIL (unknown type: %s)\n", type_string.c_str());
57   abort();
58 }
59 
60 // Unsets a dummy value from ibus config service.
UnsetConfigAndPrintResult(IBusConfig * ibus_config)61 void UnsetConfigAndPrintResult(IBusConfig* ibus_config) {
62   if (ibus_config_unset(ibus_config, kDummySection, kDummyConfigName)) {
63     printf("OK\n");
64   } else {
65     printf("FAIL\n");
66   }
67 }
68 
69 // Sets a dummy value to ibus config service. You can specify a type of the
70 // dummy value by |type_string|. "boolean", "int", "double", or "string" are
71 // allowed.
SetConfigAndPrintResult(IBusConfig * ibus_config,const std::string & type_string)72 void SetConfigAndPrintResult(
73     IBusConfig* ibus_config, const std::string& type_string) {
74   GVariant* variant = NULL;
75   GVariantClass klass = GetGVariantClassFromStringOrDie(type_string);
76 
77   switch (klass) {
78     case G_VARIANT_CLASS_BOOLEAN:
79       variant = g_variant_new_boolean(kDummyValueBoolean);
80       break;
81     case G_VARIANT_CLASS_INT32:
82       variant = g_variant_new_int32(kDummyValueInt);
83       break;
84     case G_VARIANT_CLASS_DOUBLE:
85       variant = g_variant_new_double(kDummyValueDouble);
86       break;
87     case G_VARIANT_CLASS_STRING:
88       variant = g_variant_new_string(kDummyValueString);
89       break;
90     case G_VARIANT_CLASS_ARRAY: {
91       const GVariantClass element_klass
92           = GetGVariantClassFromStringOrDie(GetElementType(type_string));
93       g_assert(element_klass != G_VARIANT_CLASS_ARRAY);
94 
95       GVariantBuilder variant_builder;
96       for (size_t i = 0; i < kArraySize; ++i) {
97         switch (element_klass) {
98           case G_VARIANT_CLASS_BOOLEAN:
99             if (i == 0) {
100               g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("ab"));
101             }
102             g_variant_builder_add(
103                 &variant_builder, "b", kDummyValueBooleanArray[i]);
104             break;
105           case G_VARIANT_CLASS_INT32:
106             if (i == 0) {
107               g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("ai"));
108             }
109             g_variant_builder_add(
110                 &variant_builder, "i", kDummyValueIntArray[i]);
111             break;
112           case G_VARIANT_CLASS_DOUBLE:
113             if (i == 0) {
114               g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("ad"));
115             }
116             g_variant_builder_add(
117                 &variant_builder, "d", kDummyValueDoubleArray[i]);
118             break;
119           case G_VARIANT_CLASS_STRING:
120             if (i == 0) {
121               g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("as"));
122             }
123             g_variant_builder_add(
124                 &variant_builder, "s", kDummyValueStringArray[i]);
125             break;
126           default:
127             printf("FAIL\n");
128             return;
129         }
130       }
131       variant = g_variant_builder_end(&variant_builder);
132       break;
133     }
134     default:
135       printf("FAIL\n");
136       return;
137   }
138   if (!variant) {
139     printf("FAIL\n");
140     return;
141   }
142   if (ibus_config_set_value(
143           ibus_config, kDummySection, kDummyConfigName, variant)) {
144     printf("OK\n");
145     return;
146   }
147   printf("FAIL\n");
148 }
149 
150 // Gets a dummy value from ibus config service. This function checks if the
151 // dummy value is |type_string| type.
GetConfigAndPrintResult(IBusConfig * ibus_config,const std::string & type_string)152 void GetConfigAndPrintResult(
153     IBusConfig* ibus_config, const std::string& type_string) {
154   GVariant* variant = ibus_config_get_value(
155       ibus_config, kDummySection, kDummyConfigName);
156   if (!variant) {
157     printf("FAIL (not found)\n");
158     return;
159   }
160   switch(g_variant_classify(variant)) {
161     case G_VARIANT_CLASS_BOOLEAN: {
162       if (g_variant_get_boolean(variant) != kDummyValueBoolean) {
163         printf("FAIL (value mismatch)\n");
164         return;
165       }
166       break;
167     }
168     case G_VARIANT_CLASS_INT32: {
169       if (g_variant_get_int32(variant) != kDummyValueInt) {
170         printf("FAIL (value mismatch)\n");
171         return;
172       }
173       break;
174     }
175     case G_VARIANT_CLASS_DOUBLE: {
176       if (g_variant_get_double(variant) != kDummyValueDouble) {
177         printf("FAIL (value mismatch)\n");
178         return;
179       }
180       break;
181     }
182     case G_VARIANT_CLASS_STRING: {
183       const char* value = g_variant_get_string(variant, NULL);
184       if (value == NULL ||
185           value != std::string(kDummyValueString)) {
186         printf("FAIL (value mismatch)\n");
187         return;
188       }
189       break;
190     }
191     case G_VARIANT_CLASS_ARRAY: {
192       const GVariantType* variant_element_type
193           = g_variant_type_element(g_variant_get_type(variant));
194       GVariantIter iter;
195       g_variant_iter_init(&iter, variant);
196 
197       size_t i;
198       GVariant* element = g_variant_iter_next_value(&iter);
199       for (i = 0; element; ++i) {
200         bool match = false;
201         if (g_variant_type_equal(
202                 variant_element_type, G_VARIANT_TYPE_BOOLEAN)) {
203           const gboolean value = g_variant_get_boolean(element);
204           match = (value == kDummyValueBooleanArray[i]);
205         } else if (g_variant_type_equal(
206             variant_element_type, G_VARIANT_TYPE_INT32)) {
207           const gint32 value = g_variant_get_int32(element);
208           match = (value == kDummyValueIntArray[i]);
209         } else if (g_variant_type_equal(
210             variant_element_type, G_VARIANT_TYPE_DOUBLE)) {
211           const gdouble value = g_variant_get_double(element);
212           match = (value == kDummyValueDoubleArray[i]);
213         } else if (g_variant_type_equal(
214             variant_element_type, G_VARIANT_TYPE_STRING)) {
215           const char* value = g_variant_get_string(element, NULL);
216           match = (value && (value == std::string(kDummyValueStringArray[i])));
217         } else {
218           printf("FAIL (list type mismatch)\n");
219           return;
220         }
221         if (!match) {
222           printf("FAIL (value mismatch)\n");
223           return;
224         }
225         g_variant_unref(element);
226         element = g_variant_iter_next_value(&iter);
227       }
228       if (i != kArraySize) {
229         printf("FAIL (invalid array)\n");
230         return;
231       }
232       break;
233     }
234     default:
235       printf("FAIL (unknown type)\n");
236       return;
237   }
238   printf("OK\n");
239 }
240 
241 // Prints out the array. It is assumed that the array contains STRING values.
242 // On success, returns true
243 // On failure, prints out "FAIL (error message)" and returns false
PrintArray(GVariant * variant)244 bool PrintArray(GVariant* variant) {
245   if (g_variant_classify(variant) != G_VARIANT_CLASS_ARRAY) {
246     printf("FAIL (Not an array)\n");
247     return false;
248   }
249   const GVariantType* variant_element_type
250       = g_variant_type_element(g_variant_get_type(variant));
251   if (!g_variant_type_equal(variant_element_type, G_VARIANT_TYPE_STRING)) {
252     printf("FAIL (Array element type is not STRING)\n");
253     return false;
254   }
255   GVariantIter iter;
256   g_variant_iter_init(&iter, variant);
257   GVariant* element = g_variant_iter_next_value(&iter);
258   while(element) {
259     const char* value = g_variant_get_string(element, NULL);
260     if (!value) {
261       printf("FAIL (Array element type is NULL)\n");
262       return false;
263     }
264     printf("%s\n", value);
265     element = g_variant_iter_next_value(&iter);
266   }
267   return true;
268 }
269 
270 // Print out the list of unused config variables from ibus.
271 // On failure, prints out "FAIL (error message)" instead.
PrintUnused(IBusConfig * ibus_config)272 void PrintUnused(IBusConfig* ibus_config) {
273   GVariant* unread = NULL;
274   GVariant* unwritten = NULL;
275   if (!ibus_config_get_unused(ibus_config, &unread, &unwritten)) {
276     printf("FAIL (get_unused failed)\n");
277     return;
278   }
279 
280   if (g_variant_classify(unread) != G_VARIANT_CLASS_ARRAY) {
281     printf("FAIL (unread is not an array)\n");
282     g_variant_unref(unread);
283     g_variant_unref(unwritten);
284     return;
285   }
286 
287   if (g_variant_classify(unwritten) != G_VARIANT_CLASS_ARRAY) {
288     printf("FAIL (unwritten is not an array)\n");
289     g_variant_unref(unread);
290     g_variant_unref(unwritten);
291     return;
292   }
293 
294   printf("Unread:\n");
295   if (!PrintArray(unread)) {
296     g_variant_unref(unread);
297     g_variant_unref(unwritten);
298     return;
299   }
300 
301   printf("Unwritten:\n");
302   if (!PrintArray(unwritten)) {
303     g_variant_unref(unread);
304     g_variant_unref(unwritten);
305     return;
306   }
307 
308   g_variant_unref(unread);
309   g_variant_unref(unwritten);
310 }
311 
312 // Set the preload engines to those named in the array |engines| of size
313 // |num_engines| and prints the result.
314 //
315 // Note that this only fails if it can't set the config value; it does not check
316 // that the names of the engines are valid.
PreloadEnginesAndPrintResult(IBusConfig * ibus_config,int num_engines,char ** engines)317 void PreloadEnginesAndPrintResult(IBusConfig* ibus_config, int num_engines,
318                                   char** engines) {
319   GVariant* variant = NULL;
320   GVariantBuilder variant_builder;
321   g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("as"));
322   for (int i = 0; i < num_engines; ++i) {
323     g_variant_builder_add(&variant_builder, "s", engines[i]);
324   }
325   variant = g_variant_builder_end(&variant_builder);
326 
327   if (ibus_config_set_value(ibus_config, kGeneralSectionName,
328                             kPreloadEnginesConfigName, variant)) {
329     printf("OK\n");
330   } else {
331     printf("FAIL\n");
332   }
333   g_variant_unref(variant);
334 }
335 
336 // Sets |engine_name| as the active IME engine.
ActivateEngineAndPrintResult(IBusBus * ibus,const char * engine_name)337 void ActivateEngineAndPrintResult(IBusBus* ibus, const char* engine_name) {
338   if (!ibus_bus_set_global_engine(ibus, engine_name)) {
339     printf("FAIL (could not start engine)\n");
340   } else {
341     printf("OK\n");
342   }
343 }
344 
345 // Prints the name of the active IME engine.
PrintActiveEngine(IBusBus * ibus)346 void PrintActiveEngine(IBusBus* ibus) {
347   IBusEngineDesc* engine_desc = ibus_bus_get_global_engine(ibus);
348   if (engine_desc) {
349     printf("%s\n", ibus_engine_desc_get_name(engine_desc));
350     g_object_unref(engine_desc);
351   } else {
352     printf("FAIL (Could not get active engine)\n");
353   }
354 }
355 
356 // Prints the names of the given engines. Takes the ownership of |engines|.
PrintEngineNames(GList * engines)357 void PrintEngineNames(GList* engines) {
358   for (GList* cursor = engines; cursor; cursor = g_list_next(cursor)) {
359     IBusEngineDesc* engine_desc = IBUS_ENGINE_DESC(cursor->data);
360     assert(engine_desc);
361     printf("%s\n", ibus_engine_desc_get_name(engine_desc));
362     g_object_unref(IBUS_ENGINE_DESC(cursor->data));
363   }
364   g_list_free(engines);
365 }
366 
PrintUsage(const char * argv0)367 void PrintUsage(const char* argv0) {
368   printf("Usage: %s COMMAND\n", argv0);
369   printf("check_reachable      Check if ibus-daemon is reachable\n");
370   printf("list_engines         List engine names (all engines)\n");
371   printf("list_active_engines  List active engine names\n");
372   // TODO(yusukes): Add 2 parameters, config_key and config_value, to
373   // set_config and get_config commands.
374   printf("set_config (boolean|int|double|string|\n"
375          "            boolean_list|int_list|double_list|string_list)\n"
376          "                     Set a dummy value to ibus config service\n");
377   printf("get_config (boolean|int|double|string\n"
378          "            boolean_list|int_list|double_list|string_list)\n"
379          "                     Get a dummy value from ibus config service\n");
380   // TODO(yusukes): Add config_key parameter to unset_config.
381   printf("unset_config         Unset a dummy value from ibus config service\n");
382   printf("get_unused           List all keys that never were used.\n");
383   printf("preload_engines      Preload the listed engines.\n");
384   printf("activate_engine      Activate the specified engine.\n");
385   printf("get_active_engine    Print the name of the current active engine.\n");
386 }
387 
388 }  // namespace
389 
main(int argc,char ** argv)390 int main(int argc, char **argv) {
391   if (argc == 1) {
392     PrintUsage(argv[0]);
393     return 1;
394   }
395 
396   ibus_init();
397   bool connected = false;
398   IBusBus* ibus = ibus_bus_new();
399   if (ibus) {
400     connected = ibus_bus_is_connected(ibus);
401   }
402 
403   const std::string command = argv[1];
404   if (command == "check_reachable") {
405     printf("%s\n", connected ? "YES" : "NO");
406     return 0;
407   } else if (!connected) {
408     printf("FAIL (Not connected)\n");
409     return 0;
410   }
411 
412   // Other commands need the bus to be connected.
413   assert(ibus);
414   assert(connected);
415   GDBusConnection* ibus_connection = ibus_bus_get_connection(ibus);
416   assert(ibus_connection);
417   IBusConfig* ibus_config = ibus_config_new(ibus_connection, NULL, NULL);
418   assert(ibus_config);
419 
420   if (command == "list_engines") {
421     PrintEngineNames(ibus_bus_list_engines(ibus));
422   } else if (command == "list_active_engines") {
423     PrintEngineNames(ibus_bus_list_active_engines(ibus));
424   } else if (command == "set_config") {
425     if (argc != 3) {
426       PrintUsage(argv[0]);
427       return 1;
428     }
429     SetConfigAndPrintResult(ibus_config, argv[2]);
430   } else if (command == "get_config") {
431     if (argc != 3) {
432       PrintUsage(argv[0]);
433       return 1;
434     }
435     GetConfigAndPrintResult(ibus_config, argv[2]);
436   } else if (command == "unset_config") {
437     UnsetConfigAndPrintResult(ibus_config);
438   } else if (command == "get_unused") {
439     PrintUnused(ibus_config);
440   } else if (command == "preload_engines") {
441     if (argc < 3) {
442       PrintUsage(argv[0]);
443       return 1;
444     }
445     PreloadEnginesAndPrintResult(ibus_config, argc-2, &(argv[2]));
446   } else if (command == "activate_engine") {
447     if (argc != 3) {
448       PrintUsage(argv[0]);
449       return 1;
450     }
451     ActivateEngineAndPrintResult(ibus, argv[2]);
452   } else if (command == "get_active_engine") {
453     PrintActiveEngine(ibus);
454   } else {
455     PrintUsage(argv[0]);
456     return 1;
457   }
458 
459   return 0;
460 }
461