Home | History | Annotate | Download | only in src
      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