Switch from ecore_strings to eina_stringshare.
[framework/uifw/edbus.git] / src / lib / notification / marshal.c
1 #include "E_Notify.h"
2 #include <string.h>
3 #include "e_notify_private.h"
4
5 void
6 e_notify_marshal_dict_variant(DBusMessageIter *iter, const char *key, char *type_str, E_DBus_Variant_Marshaller func, void *data)
7 {
8   DBusMessageIter entry, variant;
9
10   dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, "sv", &entry);
11   dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
12   func(&entry, data);
13   dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, type_str, &variant);
14   func(&variant, data);
15   dbus_message_iter_close_container(&entry, &variant);
16   dbus_message_iter_close_container(iter, &entry);
17 }
18
19 void
20 e_notify_marshal_dict_string(DBusMessageIter *iter, const char *key, const char *value)
21 {
22   DBusMessageIter entry, variant;
23
24   dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, "sv", &entry);
25   dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
26   dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "s", &variant);
27   dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value);
28   dbus_message_iter_close_container(&entry, &variant);
29   dbus_message_iter_close_container(iter, &entry);
30 }
31
32 void
33 e_notify_marshal_dict_byte(DBusMessageIter *iter, const char *key, char value)
34 {
35   DBusMessageIter entry, variant;
36
37   if (!key || !value) return;
38
39   dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
40   dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
41   dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "y", &variant);
42   dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &value);
43   dbus_message_iter_close_container(&entry, &variant);
44   dbus_message_iter_close_container(iter, &entry);
45 }
46
47 void
48 e_notify_marshal_dict_int(DBusMessageIter *iter, const char *key, int value)
49 {
50   DBusMessageIter entry, variant;
51
52   if (!key || !value) return;
53
54   dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, "sv", &entry);
55   dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
56   dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "i", &variant);
57   dbus_message_iter_append_basic(&variant, DBUS_TYPE_INT32, &value);
58   dbus_message_iter_close_container(&entry, &variant);
59   dbus_message_iter_close_container(iter, &entry);
60 }
61
62 void
63 e_notify_marshal_string_array(DBusMessageIter *iter, const char **strings)
64 {
65   const char **str;
66   DBusMessageIter arr;
67
68   dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &arr);
69
70   for (str = strings; *str; str++)
71     dbus_message_iter_append_basic(&arr, DBUS_TYPE_STRING, str);
72
73   dbus_message_iter_close_container(iter, &arr);
74 }
75
76 void
77 e_notify_marshal_string_list_as_array(DBusMessageIter *iter, Ecore_List *strings)
78 {
79   const char *str;
80   DBusMessageIter arr;
81
82   dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &arr);
83
84   ecore_list_first_goto(strings);
85   while((str = ecore_list_next(strings)))
86     dbus_message_iter_append_basic(&arr, DBUS_TYPE_STRING, &str);
87
88   dbus_message_iter_close_container(iter, &arr);
89 }
90
91 Ecore_List *
92 e_notify_unmarshal_string_array_as_list(DBusMessageIter *iter, DBusError *err)
93 {
94   Ecore_List *strings;
95   char *sig;
96   int ret;
97   DBusMessageIter arr;
98
99   sig = dbus_message_iter_get_signature(iter);
100   ret = !strcmp(sig, "as");
101   dbus_free(sig);
102   if (!ret) return NULL;
103
104   strings = ecore_list_new();
105   ecore_list_free_cb_set(strings, ECORE_FREE_CB(free)); //XXX use eina_stringshare_release?
106
107   dbus_message_iter_recurse(iter, &arr);
108   while(dbus_message_iter_has_next(&arr))
109   {
110     const char *str;
111     dbus_message_iter_get_basic(&arr, &str);
112     ecore_list_append(strings, strdup(str)); //XXX use eina_stringshare_instance?
113     dbus_message_iter_next(&arr);
114   }
115   return strings;
116 }
117
118
119
120 DBusMessage *
121 e_notify_marshal_get_capabilities()
122 {
123   DBusMessage *msg;
124
125   msg = e_notification_call_new("GetCapabilities");
126   return msg;
127 }
128
129 DBusMessage *
130 e_notify_marshal_get_capabilities_return(DBusMessage *method_call, const char **capabilities)
131 {
132   DBusMessage *msg;
133   DBusMessageIter iter;
134
135   msg = dbus_message_new_method_return(method_call);
136   dbus_message_iter_init_append(msg, &iter);
137   e_notify_marshal_string_array(&iter, capabilities);
138
139   return msg;
140 }
141
142 void *
143 e_notify_unmarshal_get_capabilities_return(DBusMessage *msg, DBusError *err)
144 {
145   DBusMessageIter iter;
146   E_Notification_Return_Get_Capabilities *ret;
147
148   if (!dbus_message_has_signature(msg, "as")) return NULL;
149
150   ret = calloc(1, sizeof(E_Notification_Return_Get_Capabilities));
151   dbus_message_iter_init(msg, &iter);
152   ret->capabilities = e_notify_unmarshal_string_array_as_list(&iter, err);
153
154   return ret;
155 }
156
157 void
158 e_notify_free_get_capabilities_return(void *data)
159 {
160   E_Notification_Return_Get_Capabilities *ret = data;
161
162   if (!ret) return;
163   ecore_list_destroy(ret->capabilities);
164   free(ret);
165 }
166
167 DBusMessage *
168 e_notify_marshal_get_server_information()
169 {
170   DBusMessage *msg;
171
172   msg = e_notification_call_new("GetServerInformation");
173   return msg;
174 }
175
176 DBusMessage *
177 e_notify_marshal_get_server_information_return(DBusMessage *method_call, const char *name, const char *vendor, const char *version)
178 {
179   DBusMessage *msg;
180   msg = dbus_message_new_method_return(method_call);
181   dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &vendor, DBUS_TYPE_STRING, &version, DBUS_TYPE_INVALID);
182   return msg;
183 }
184
185 void *
186 e_notify_unmarshal_get_server_information_return(DBusMessage *msg, DBusError *err)
187 {
188   E_Notification_Return_Get_Server_Information *info;
189   if (!dbus_message_has_signature(msg, "sss")) return NULL;
190
191   info = calloc(1, sizeof(E_Notification_Return_Get_Server_Information));
192   dbus_message_get_args(msg, err,
193     DBUS_TYPE_STRING, &(info->name),
194     DBUS_TYPE_STRING, &(info->vendor),
195     DBUS_TYPE_STRING, &(info->version),
196     DBUS_TYPE_INVALID
197   );
198   if (dbus_error_is_set(err))
199   {
200     free(info);
201     return NULL;
202   }
203
204   return info;
205 }
206
207 void
208 e_notify_free_get_server_information_return(void *data)
209 {
210   E_Notification_Return_Get_Server_Information *info = data;
211
212   if (!info) return;
213   free(info);
214 }
215
216 DBusMessage *
217 e_notify_marshal_close_notification(dbus_uint32_t id)
218 {
219   DBusMessage *msg;
220
221   msg = e_notification_call_new("CloseNotification");
222   dbus_message_append_args(msg, DBUS_TYPE_UINT32, &id, DBUS_TYPE_INVALID);
223   return msg;
224 }
225
226 dbus_uint32_t
227 e_notify_unmarshal_close_notification(DBusMessage *msg, DBusError *err)
228 {
229   dbus_uint32_t id;
230   if (!dbus_message_has_signature(msg, "u")) return 0;
231   dbus_message_get_args(msg, err, DBUS_TYPE_UINT32, &id, DBUS_TYPE_INVALID);
232   if (err && dbus_error_is_set(err))
233     return 0;
234
235   return id;
236 }
237
238 DBusMessage *
239 e_notify_marshal_notification_closed_signal(dbus_uint32_t id, dbus_uint32_t reason)
240 {
241   DBusMessage *msg;
242   msg = dbus_message_new_signal(E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, "NotificationClosed");
243   dbus_message_append_args(msg, DBUS_TYPE_UINT32, &id, DBUS_TYPE_UINT32, &reason, DBUS_TYPE_INVALID);
244   return msg;
245 }
246
247 E_Notification_Event_Notification_Closed *
248 e_notify_unmarshal_notification_closed_signal(DBusMessage *msg, DBusError *err)
249 {
250   E_Notification_Event_Notification_Closed *ev;
251
252   if (!dbus_message_has_signature(msg, "uu")) 
253   {
254     dbus_set_error(err, DBUS_ERROR_INVALID_SIGNATURE, "");
255     return NULL;
256   }
257   ev = calloc(1, sizeof(E_Notification_Event_Notification_Closed));
258   dbus_message_get_args(msg, err, DBUS_TYPE_UINT32, &(ev->notification_id), DBUS_TYPE_UINT32, &(ev->reason), DBUS_TYPE_INVALID);
259   if (dbus_error_is_set(err))
260   {
261     free(ev);
262     return NULL;
263   }
264   return ev;
265 }
266
267 DBusMessage *
268 e_notify_marshal_action_invoked_signal(dbus_uint32_t id, const char *action_id)
269 {
270   DBusMessage *msg;
271   msg = dbus_message_new_signal(E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, "ActionInvoked");
272   dbus_message_append_args(msg, DBUS_TYPE_UINT32, &id, DBUS_TYPE_STRING, &action_id, DBUS_TYPE_INVALID);
273   return msg;
274 }
275
276 E_Notification_Event_Action_Invoked *
277 e_notify_unmarshal_action_invoked_signal(DBusMessage *msg, DBusError *err)
278 {
279   E_Notification_Event_Action_Invoked *ev;
280
281   if (!dbus_message_has_signature(msg, "us")) 
282   {
283     dbus_set_error(err, DBUS_ERROR_INVALID_SIGNATURE, "");
284     return NULL;
285   }
286   ev = calloc(1, sizeof(E_Notification_Event_Action_Invoked));
287   dbus_message_get_args(msg, err, DBUS_TYPE_UINT32, &(ev->notification_id), DBUS_TYPE_STRING, &(ev->action_id), DBUS_TYPE_INVALID);
288   if (dbus_error_is_set(err))
289   {
290     free(ev);
291     return NULL;
292   }
293   return ev;
294 }
295
296 DBusMessage *
297 e_notify_marshal_notify(E_Notification *n)
298 {
299   DBusMessage *msg;
300   DBusMessageIter iter, sub;
301
302   if (!n->app_name) n->app_name = strdup("");
303   if (!n->app_icon) n->app_icon = strdup("");
304   if (!n->summary) n->summary = strdup("");
305   if (!n->body) n->body = strdup("");
306
307   msg = e_notification_call_new("Notify");
308   dbus_message_append_args(msg, 
309     DBUS_TYPE_STRING, &(n->app_name),
310     DBUS_TYPE_UINT32, &(n->replaces_id),
311     DBUS_TYPE_STRING, &(n->app_icon),
312     DBUS_TYPE_STRING, &(n->summary),
313     DBUS_TYPE_STRING, &(n->body),
314     DBUS_TYPE_INVALID
315   );
316
317   dbus_message_iter_init_append(msg, &iter);
318   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub);
319   if (n->actions)
320   {
321     E_Notification_Action *action;
322     ecore_list_first_goto(n->actions);
323     while ((action = ecore_list_next(n->actions)))
324     {
325       dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &(action->id));
326       dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &(action->name));
327     }
328   }
329   dbus_message_iter_close_container(&iter, &sub);
330
331   /* hints */
332   dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub);
333   if (n->hints.urgency) /* we only need to send this if its non-zero*/
334     e_notify_marshal_dict_byte(&sub, "urgency", n->hints.urgency);
335   if (n->hints.category)
336     e_notify_marshal_dict_string(&sub, "category", n->hints.category);
337   if (n->hints.desktop)
338     e_notify_marshal_dict_string(&sub, "desktop_entry", n->hints.desktop);
339   if (n->hints.image_data)
340     e_notify_marshal_dict_variant(&sub, "image_data", "(iiibiiay)", E_DBUS_VARIANT_MARSHALLER(e_notify_marshal_hint_image), n->hints.image_data);
341   if (n->hints.icon_data)
342     e_notify_marshal_dict_variant(&sub, "icon_data", "(iiibiiay)", E_DBUS_VARIANT_MARSHALLER(e_notify_marshal_hint_image), n->hints.icon_data);
343   if (n->hints.sound_file)
344     e_notify_marshal_dict_string(&sub, "sound_file", n->hints.sound_file);
345   if (n->hints.suppress_sound) /* we only need to send this if its true */
346     e_notify_marshal_dict_byte(&sub, "suppress_sound", n->hints.suppress_sound);
347   if (n->hints.x > -1 && n->hints.y > -1)
348   {
349     e_notify_marshal_dict_int(&sub, "x", n->hints.x);
350     e_notify_marshal_dict_int(&sub, "y", n->hints.y);
351   }
352
353   dbus_message_iter_close_container(&iter, &sub);
354   dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &(n->expire_timeout));
355   return msg;
356 }
357
358 E_Notification *
359 e_notify_unmarshal_notify(DBusMessage *msg, DBusError *err)
360 {
361   E_Notification *n;
362   const char *s_val;
363   dbus_uint32_t u_val;
364   dbus_int32_t i_val;
365   DBusMessageIter iter;
366   if (!dbus_message_has_signature(msg, "susssasa{sv}i")) return NULL;
367
368   n = e_notification_new();
369   if (!n) return NULL;
370   dbus_message_iter_init(msg, &iter);
371
372   dbus_message_iter_get_basic(&iter, &s_val);
373   e_notification_app_name_set(n, s_val); 
374   dbus_message_iter_next(&iter);
375
376   dbus_message_iter_get_basic(&iter, &u_val);
377   e_notification_replaces_id_set(n, u_val); 
378   dbus_message_iter_next(&iter);
379
380   dbus_message_iter_get_basic(&iter, &s_val);
381   e_notification_app_icon_set(n, s_val); 
382   dbus_message_iter_next(&iter);
383
384   dbus_message_iter_get_basic(&iter, &s_val);
385   e_notification_summary_set(n, s_val); 
386   dbus_message_iter_next(&iter);
387
388   dbus_message_iter_get_basic(&iter, &s_val);
389   e_notification_body_set(n, s_val); 
390   dbus_message_iter_next(&iter);
391
392   e_notify_unmarshal_notify_actions(n, &iter);
393   dbus_message_iter_next(&iter);
394
395   e_notify_unmarshal_notify_hints(n, &iter);
396   dbus_message_iter_next(&iter);
397
398   dbus_message_iter_get_basic(&iter, &i_val);
399   e_notification_timeout_set(n, i_val);
400   
401   return n;
402 }
403
404 DBusMessage *
405 e_notify_marshal_notify_return(DBusMessage *method_call, dbus_uint32_t notification_id)
406 {
407   DBusMessage *msg;
408   msg = dbus_message_new_method_return(method_call);
409   dbus_message_append_args(msg, DBUS_TYPE_UINT32, &notification_id, DBUS_TYPE_INVALID);
410   return msg;
411 }
412
413 void *
414 e_notify_unmarshal_notify_return(DBusMessage *msg, DBusError *err)
415 {
416   E_Notification_Return_Notify *ret;
417   ret = calloc(1, sizeof(E_Notification_Return_Notify));
418   dbus_message_get_args(msg, err, DBUS_TYPE_UINT32, &(ret->notification_id), DBUS_TYPE_INVALID);
419   if (dbus_error_is_set(err))
420   {
421     free(ret);
422     return NULL;
423   }
424   return ret;
425 }
426
427 void
428 e_notify_free_notify_return(void *data)
429 {
430   E_Notification_Return_Notify *ret = data;
431
432   if (!ret) return;
433   free(ret);
434 }
435
436 void
437 e_notify_unmarshal_notify_actions(E_Notification *n, DBusMessageIter *iter)
438 {
439   DBusMessageIter arr;
440   const char *id, *name;
441   dbus_message_iter_recurse(iter, &arr);
442   while (dbus_message_iter_has_next(&arr))
443   {
444     dbus_message_iter_get_basic(&arr, &id);
445     dbus_message_iter_next(&arr);
446     dbus_message_iter_get_basic(&arr, &name);
447     dbus_message_iter_next(&arr);
448     e_notification_action_add(n, id, name);
449   }
450 }
451
452 void
453 e_notify_unmarshal_notify_hints(E_Notification *n, DBusMessageIter *iter)
454 {
455   DBusMessageIter arr;
456   const char *key;
457   int x_set = 0, y_set = 0;
458   int x, y;
459   dbus_message_iter_recurse(iter, &arr);
460   
461   if (dbus_message_iter_get_arg_type(&arr) == DBUS_TYPE_INVALID)
462     return;
463   
464   do
465   {
466     DBusMessageIter dict;
467     dbus_message_iter_recurse(&arr, &dict);
468     do
469     {
470       DBusMessageIter variant;
471       const char *s_val;
472       char y_val;
473       dbus_bool_t b_val;
474
475       dbus_message_iter_get_basic(&dict, &key);
476       dbus_message_iter_next(&dict);
477       dbus_message_iter_recurse(&dict, &variant);
478      
479       if (!strcmp(key, "urgency"))
480         {
481           dbus_message_iter_get_basic(&variant, &y_val);
482           e_notification_hint_urgency_set(n, y_val);
483         }
484       else if (!strcmp(key, "category"))
485         {
486           dbus_message_iter_get_basic(&variant, &s_val);
487           e_notification_hint_category_set(n, s_val);
488         }
489       else if (!strcmp(key, "desktop-entry"))
490         {
491           e_notification_hint_desktop_set(n, s_val);
492         }
493       else if (!strcmp(key, "sound-file"))
494         {
495           dbus_message_iter_get_basic(&variant, &s_val);
496           e_notification_hint_sound_file_set(n, s_val);
497         }
498       else if (!strcmp(key, "suppress-sound"))
499         {
500           dbus_message_iter_get_basic(&variant, &b_val);
501           e_notification_hint_suppress_sound_set(n, b_val);
502         }
503       else if (!strcmp(key, "x"))
504       {
505         dbus_message_iter_get_basic(&variant, &x);
506         x_set = 1;
507       }
508       else if (!strcmp(key, "y"))
509       {
510         dbus_message_iter_get_basic(&variant, &y);
511         y_set = 1;
512       }
513       else if (!strcmp(key, "image_data"))
514         {
515           dbus_message_iter_recurse(&dict, &variant);
516           n->hints.image_data = e_notify_unmarshal_hint_image(&variant);
517         }
518       else if (!strcmp(key, "icon_data"))
519         {
520           dbus_message_iter_recurse(&dict, &variant);
521           n->hints.icon_data = e_notify_unmarshal_hint_image(&variant);
522         }
523     }
524     while (dbus_message_iter_next(&dict));
525   } 
526   while (dbus_message_iter_next(&arr));
527
528   if (x_set && y_set)
529     e_notification_hint_xy_set(n, x, y);
530 }
531
532 void
533 e_notify_marshal_hint_image(DBusMessageIter *iter, E_Notification_Image *img)
534 {
535   DBusMessageIter sub, arr;
536   int data_len = 0; 
537
538   data_len = ((img->height - 1) * img->rowstride) + (img->width * ((img->channels * (img->bits_per_sample + 7)) / 8));
539   dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &sub);
540   dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->width));
541   dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->height));
542   dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->rowstride));
543   dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &(img->has_alpha));
544   dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->bits_per_sample));
545   dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &(img->channels));
546   dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, NULL, &arr);
547   dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(img->data), data_len);
548   dbus_message_iter_close_container(&sub, &arr);
549 }
550
551 E_Notification_Image *
552 e_notify_unmarshal_hint_image(DBusMessageIter *iter)
553 {
554   DBusMessageIter sub, arr;
555   char *byte_array;
556   int array_len;
557   E_Notification_Image *img;
558   char *sig;
559   int sig_matches;
560
561   sig = dbus_message_iter_get_signature(iter);
562   sig_matches = strcmp(sig, "(iiibiiay)");
563   dbus_free(sig);
564   if (sig_matches) return NULL;
565
566   img = e_notification_image_new();
567   if (!img) return NULL;
568
569   dbus_message_iter_recurse(iter, &sub);
570   dbus_message_iter_get_basic(&sub, &(img->width));
571   dbus_message_iter_next(&sub);
572   dbus_message_iter_get_basic(&sub, &(img->height));
573   dbus_message_iter_next(&sub);
574   dbus_message_iter_get_basic(&sub, &(img->rowstride));
575   dbus_message_iter_next(&sub);
576   dbus_message_iter_get_basic(&sub, &(img->has_alpha));
577   dbus_message_iter_next(&sub);
578   dbus_message_iter_get_basic(&sub, &(img->bits_per_sample));
579   dbus_message_iter_next(&sub);
580   dbus_message_iter_get_basic(&sub, &(img->channels));
581   dbus_message_iter_next(&sub);
582
583   dbus_message_iter_recurse(&sub, &arr);
584   dbus_message_iter_get_fixed_array(&arr, &(byte_array), &array_len);
585   img->data = malloc(array_len);
586   memcpy(img->data, byte_array, array_len);
587
588   return img;
589 }
590