tmisu

Notification to stdout daemon
git clone https://git.inz.fi/tmisu/
Log | Files | Refs | README | LICENSE

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