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"). 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. 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. 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. 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. 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 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. 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. 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. 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. 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|. 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 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 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