output.c (6315B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <inttypes.h> 4 #include <string.h> 5 6 #include "output.h" 7 #include "tmisu.h" 8 9 static void print_sanitized(const char *string, const char *escape) { 10 while (*string) { 11 size_t len = strcspn(string, escape); 12 printf("%.*s", (int)len, string); 13 string += len; 14 while (*string && strchr(escape, *string)) { 15 if (*string == '\n') 16 printf("\\n"); 17 else 18 printf("\\%c", *string); 19 string++; 20 } 21 } 22 } 23 24 static void hints_output_iterator(DBusMessageIter *hints, const char *key_prefix, const char *key_suffix, const char *str_prefix, const char *str_suffix, const char *escape, const char *delimiter, int join) 25 { 26 const char *d = ""; 27 for (; dbus_message_iter_get_arg_type(hints) != DBUS_TYPE_INVALID; dbus_message_iter_next(hints), d = delimiter) { 28 DBusMessageIter dictentry; 29 DBusMessageIter variant; 30 DBusBasicValue value; 31 const char *key; 32 33 dbus_message_iter_recurse(hints, &dictentry); 34 dbus_message_iter_get_basic(&dictentry, &key); 35 dbus_message_iter_next(&dictentry); 36 dbus_message_iter_recurse(&dictentry, &variant); 37 38 printf("%s%s", d, key_prefix); 39 print_sanitized(key, escape); 40 printf("%s", key_suffix); 41 42 if (!dbus_type_is_basic(dbus_message_iter_get_arg_type(&variant))) { 43 printf("null"); 44 continue; 45 } 46 47 dbus_message_iter_get_basic(&variant, &value); 48 49 switch (dbus_message_iter_get_arg_type(&variant)) { 50 case DBUS_TYPE_BYTE: 51 printf("%" PRIu8, value.byt); 52 break; 53 case DBUS_TYPE_BOOLEAN: 54 printf("%s", value.bool_val ? "true" : "false"); 55 break; 56 case DBUS_TYPE_INT16: 57 printf("%" PRId16, value.i16); 58 break; 59 case DBUS_TYPE_UINT16: 60 printf("%" PRIu16, value.u16); 61 break; 62 case DBUS_TYPE_INT32: 63 printf("%" PRId32, value.i32); 64 break; 65 case DBUS_TYPE_UINT32: 66 printf("%" PRIu32, value.u32); 67 break; 68 case DBUS_TYPE_INT64: 69 printf("%" PRId64, value.i64); 70 break; 71 case DBUS_TYPE_UINT64: 72 printf("%" PRIu64, value.u64); 73 break; 74 case DBUS_TYPE_DOUBLE: 75 printf("%lf", value.dbl); 76 break; 77 case DBUS_TYPE_STRING: 78 case DBUS_TYPE_OBJECT_PATH: 79 dbus_message_iter_get_basic(&variant, &value); 80 printf("%s", str_prefix); 81 print_sanitized(value.str, escape); 82 printf("%s", str_suffix); 83 continue; 84 break; 85 default: 86 printf("null%s", d); 87 continue; 88 } 89 } 90 91 if (!join && d == delimiter) 92 printf("%s", delimiter); 93 } 94 95 static void default_output(const char *app_name, const char *app_icon, dbus_uint32_t id, dbus_uint32_t replaces_id, 96 dbus_int32_t timeout, DBusMessageIter *hints, DBusMessageIter *actions, const char *summary, 97 const char *body, const char *delimiter) 98 { 99 (void)id; 100 printf("app_name: "); 101 print_sanitized(app_name, "\n\\"); 102 printf("%sapp_icon: ", delimiter); 103 print_sanitized(app_icon, "\n\\"); 104 printf("%sreplaces_id: %" PRIu32 "%stimeout: %" PRId32 "%s", delimiter, 105 replaces_id, delimiter, 106 timeout, delimiter); 107 108 printf("hints:%s", delimiter); 109 hints_output_iterator(hints, "\t", ": ", "", "", "\n\\", delimiter, 0); 110 111 printf("actions:%s", delimiter); 112 while (dbus_message_iter_get_arg_type(actions) != DBUS_TYPE_INVALID) { 113 if (!dbus_message_iter_has_next(actions)) 114 break; 115 const char *key; 116 const char *value; 117 118 dbus_message_iter_get_basic(actions, &key); 119 dbus_message_iter_next(actions); 120 dbus_message_iter_get_basic(actions, &value); 121 dbus_message_iter_next(actions); 122 123 printf("\t"); 124 print_sanitized(key, "\n\\"); 125 printf(": "); 126 print_sanitized(value, "\n\\"); 127 printf("%s", delimiter); 128 } 129 130 printf("body: "); 131 print_sanitized(body, "\n\\"); 132 printf("%ssummary: ", delimiter); 133 print_sanitized(summary, "\n\\"); 134 printf("%s", delimiter); 135 } 136 137 static void json_output(const char *app_name, const char *app_icon, dbus_uint32_t id, dbus_uint32_t replaces_id, 138 dbus_int32_t timeout, DBusMessageIter *hints, DBusMessageIter *actions, const char *summary, 139 const char *body, const char *delimiter) { 140 const char *sep = ""; 141 printf("{" 142 "\"id\": %" PRIu32 ", " 143 "\"app_name\": \"", id); 144 print_sanitized(app_name, "\n\\\""); 145 printf("\", " 146 "\"app_icon\": \""); 147 print_sanitized(app_icon, "\n\\\""); 148 printf("\", " 149 "\"replaces_id\": %" PRIu32 ", " 150 "\"timeout\": %" PRId32 ", ", 151 replaces_id, timeout); 152 153 printf("\"hints\": {"); 154 hints_output_iterator(hints, "\"", "\": ", "\"", "\"", "\n\\\"", ", ", 1); 155 printf("}, \"actions\": {"); 156 157 while (dbus_message_iter_get_arg_type(actions) != DBUS_TYPE_INVALID) { 158 if (!dbus_message_iter_has_next(actions)) 159 break; 160 const char *key; 161 const char *value; 162 163 dbus_message_iter_get_basic(actions, &key); 164 dbus_message_iter_next(actions); 165 dbus_message_iter_get_basic(actions, &value); 166 dbus_message_iter_next(actions); 167 168 printf("\""); 169 print_sanitized(key, "\n\\\""); 170 printf("\": \""); 171 print_sanitized(value, "\n\\\""); 172 printf("\"%s", sep); 173 sep = ", "; 174 } 175 176 printf("}, "); 177 printf("\"summary\": \""); 178 print_sanitized(summary, "\n\\\""); 179 printf("\", " 180 "\"body\": \""); 181 print_sanitized(body, "\n\\\""); 182 printf("\"}%s", delimiter); 183 } 184 185 void output_notification(DBusMessage *message, dbus_uint32_t id, enum output_format fmt, const char *delimiter) 186 { 187 DBusMessageIter i; 188 DBusMessageIter actions; 189 DBusMessageIter hints; 190 const char *app_name; 191 dbus_uint32_t replaces_id; 192 dbus_int32_t timeout; 193 const char *app_icon; 194 const char *summary; 195 const char *body; 196 197 dbus_message_iter_init(message, &i); 198 dbus_message_iter_get_basic(&i, &app_name); 199 dbus_message_iter_next(&i); 200 dbus_message_iter_get_basic(&i, &replaces_id); 201 dbus_message_iter_next(&i); 202 dbus_message_iter_get_basic(&i, &app_icon); 203 dbus_message_iter_next(&i); 204 dbus_message_iter_get_basic(&i, &summary); 205 dbus_message_iter_next(&i); 206 dbus_message_iter_get_basic(&i, &body); 207 208 dbus_message_iter_next(&i); 209 dbus_message_iter_recurse(&i, &actions); 210 211 dbus_message_iter_next(&i); 212 dbus_message_iter_recurse(&i, &hints); 213 214 dbus_message_iter_next(&i); 215 dbus_message_iter_get_basic(&i, &timeout); 216 217 switch (fmt) { 218 case FORMAT_JSON: 219 json_output(app_name, app_icon, id, replaces_id, 220 timeout, &hints, &actions, summary, body, 221 delimiter); 222 break; 223 case FORMAT_TEXT: 224 default: 225 default_output(app_name, app_icon, id, replaces_id, 226 timeout, &hints, &actions, summary, body, 227 delimiter); 228 } 229 230 fflush(stdout); 231 } 232