1 #include "e.h"
2 #include "e_mod_main.h"
3 #include "e_mod_packagekit.h"
4 
5 
6 /* GUI */
7 void
packagekit_icon_update(E_PackageKit_Module_Context * ctxt,Eina_Bool working)8 packagekit_icon_update(E_PackageKit_Module_Context *ctxt,
9                        Eina_Bool working)
10 {
11    E_PackageKit_Instance *inst;
12    E_PackageKit_Package *pkg;
13    unsigned count = 0;
14    const char *state;
15    char buf[16];
16    Eina_List *l;
17 
18    if (!ctxt->instances)
19      return;
20 
21    if (working)
22      state = "packagekit,state,working";
23    else if (ctxt->error)
24      state = "packagekit,state,error";
25    else
26      {
27         EINA_LIST_FOREACH(ctxt->packages, l, pkg)
28           {
29              switch (pkg->info)
30                {
31                   case PK_INFO_ENUM_LOW:
32                   case PK_INFO_ENUM_ENHANCEMENT:
33                   case PK_INFO_ENUM_NORMAL:
34                   case PK_INFO_ENUM_BUGFIX:
35                   case PK_INFO_ENUM_IMPORTANT:
36                   case PK_INFO_ENUM_SECURITY:
37                   case PK_INFO_ENUM_AVAILABLE:
38                      count++;
39                      break;
40                   default:
41                      break;
42                }
43           }
44 
45         if (count > 0)
46           state = "packagekit,state,updates";
47         else
48           state = "packagekit,state,updated";
49      }
50 
51    //DBG("PKGKIT: IconUpdate, %d updates available (%s)", count, state);
52 
53    if (count) snprintf(buf, sizeof(buf), "%d", count);
54    EINA_LIST_FOREACH(ctxt->instances, l, inst)
55      {
56         edje_object_signal_emit(inst->gadget, state, "e");
57         edje_object_part_text_set(inst->gadget, "num_updates", count ? buf : "");
58      }
59 }
60 
61 static void
_update_button_cb(void * data,Evas_Object * obj EINA_UNUSED,void * event EINA_UNUSED)62 _update_button_cb(void *data, Evas_Object *obj EINA_UNUSED,
63                   void *event EINA_UNUSED)
64 {
65    E_PackageKit_Instance *inst = data;
66 
67    packagekit_create_transaction_and_exec(inst->ctxt, packagekit_refresh_cache);
68 }
69 
70 static char *
_help_gl_text_get(void * data,Evas_Object * obj EINA_UNUSED,const char * part)71 _help_gl_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
72 {
73    PackageKit_Package_Info info = (PackageKit_Package_Info)data;
74 
75    if (strcmp(part, "elm.text"))
76       return NULL;
77 
78    switch (info)
79      {
80         case PK_INFO_ENUM_LOW:
81           return strdup(_("Low priority update"));
82         case PK_INFO_ENUM_ENHANCEMENT:
83           return strdup(_("Enhancement update"));
84         case PK_INFO_ENUM_NORMAL:
85           return strdup(_("Normal update"));
86         case PK_INFO_ENUM_BUGFIX:
87           return strdup(_("Bugfix update"));
88         case PK_INFO_ENUM_IMPORTANT:
89           return strdup(_("High priority update"));
90         case PK_INFO_ENUM_SECURITY:
91           return strdup(_("Security update"));
92         default:
93           return NULL;
94      }
95 }
96 
97 static Evas_Object *
_help_gl_content_get(void * data,Evas_Object * obj,const char * part)98 _help_gl_content_get(void *data, Evas_Object *obj, const char *part)
99 {
100    PackageKit_Package_Info info = (PackageKit_Package_Info)data;
101    const char *emblem_name;
102    Evas_Object *icon;
103 
104    if (strcmp(part, "elm.swallow.icon"))
105       return NULL;
106 
107    switch (info)
108      {
109         case PK_INFO_ENUM_LOW:
110           emblem_name = "e/modules/packagekit/icon/low"; break;
111         case PK_INFO_ENUM_ENHANCEMENT:
112           emblem_name = "e/modules/packagekit/icon/enhancement"; break;
113         case PK_INFO_ENUM_NORMAL:
114           emblem_name = "e/modules/packagekit/icon/normal"; break;
115         case PK_INFO_ENUM_BUGFIX:
116           emblem_name = "e/modules/packagekit/icon/bugfix"; break;
117         case PK_INFO_ENUM_IMPORTANT:
118           emblem_name = "e/modules/packagekit/icon/important"; break;
119         case PK_INFO_ENUM_SECURITY:
120           emblem_name = "e/modules/packagekit/icon/security"; break;
121         default:
122           return NULL; break;
123      }
124 
125    icon = edje_object_add(evas_object_evas_get(obj));
126    e_theme_edje_object_set(icon, "base/theme/modules/packagekit", emblem_name);
127 
128    return icon;
129 }
130 
131 static void
_help_button_cb(void * data,Evas_Object * obj EINA_UNUSED,void * event EINA_UNUSED)132 _help_button_cb(void *data, Evas_Object *obj EINA_UNUSED,
133                 void *event EINA_UNUSED)
134 {
135    E_PackageKit_Instance *inst = data;
136    Elm_Genlist_Item_Class *help_itc;
137    char buf[1024];
138    long i;
139 
140    if (inst->popup_help_mode)
141      {
142         inst->popup_help_mode = EINA_FALSE;
143         packagekit_popup_update(inst, EINA_TRUE);
144         return;
145      }
146    inst->popup_help_mode = EINA_TRUE;
147 
148    // special item class for help items
149    help_itc = elm_genlist_item_class_new();
150    help_itc->item_style = "default";
151    help_itc->func.text_get = _help_gl_text_get;
152    help_itc->func.content_get = _help_gl_content_get;
153 
154    // repopulate the genlist
155    elm_genlist_clear(inst->popup_genlist);
156    for (i = PK_INFO_ENUM_LOW; i <= PK_INFO_ENUM_SECURITY; i++)
157      {
158         Elm_Genlist_Item *it;
159         it = elm_genlist_item_append(inst->popup_genlist, help_itc, (void*)i,
160                                      NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
161         elm_genlist_item_select_mode_set(it, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
162      }
163 
164    elm_genlist_item_class_free(help_itc);
165 
166    // update title label
167    if (inst->ctxt->v_maj != -1)
168      snprintf(buf, sizeof(buf), "PackageKit version: %d.%d.%d",
169               inst->ctxt->v_maj, inst->ctxt->v_min, inst->ctxt->v_mic);
170    else
171      snprintf(buf, sizeof(buf), _("Unknown PackageKit version"));
172    elm_object_text_set(inst->popup_title_entry, buf);
173 }
174 
175 static void
_install_button_cb(void * data,Evas_Object * obj EINA_UNUSED,void * event EINA_UNUSED)176 _install_button_cb(void *data, Evas_Object *obj EINA_UNUSED,
177                    void *event EINA_UNUSED)
178 {
179    E_PackageKit_Instance *inst = data;
180    E_PackageKit_Package *pkg;
181    const Eina_List *selected;
182    Elm_Genlist_Item *item;
183    Eina_List *l;
184 
185    selected = elm_genlist_selected_items_get(inst->popup_genlist);
186    if (!selected)
187      {
188         // nothing selected, update all packages
189         EINA_LIST_FOREACH(inst->ctxt->packages, l, pkg)
190           pkg->to_be_installed = EINA_TRUE;
191      }
192    else
193      {
194         // only updated selected packages
195         EINA_LIST_FOREACH(inst->ctxt->packages, l, pkg)
196           pkg->to_be_installed = EINA_FALSE;
197         EINA_LIST_FOREACH((Eina_List*)selected, l, item)
198           {
199              pkg = elm_object_item_data_get(item);
200              pkg->to_be_installed = EINA_TRUE;
201           }
202      }
203 
204    packagekit_create_transaction_and_exec(inst->ctxt, packagekit_update_packages);
205 }
206 
207 static void
_run_button_cb(void * data,Evas_Object * obj EINA_UNUSED,void * event EINA_UNUSED)208 _run_button_cb(void *data, Evas_Object *obj EINA_UNUSED,
209                void *event EINA_UNUSED)
210 {
211    E_PackageKit_Instance *inst = data;
212    packagekit_popup_del(inst);
213 
214    e_exec(e_zone_current_get(), NULL,
215           inst->ctxt->config->manager_command,
216           NULL, NULL);
217 }
218 
219 void
packagekit_popup_update(E_PackageKit_Instance * inst,Eina_Bool rebuild_list)220 packagekit_popup_update(E_PackageKit_Instance *inst, Eina_Bool rebuild_list)
221 {
222    E_PackageKit_Module_Context *ctxt = inst->ctxt;
223    E_PackageKit_Package *pkg;
224    const Eina_List *selected;
225    unsigned num_updates = 0;
226    char buf[1024];
227    Eina_List *l;
228 
229    if (!inst->popup_genlist) return;
230 
231    if (inst->popup_help_mode)
232      inst->popup_help_mode = EINA_FALSE;
233 
234    if (rebuild_list)
235      elm_genlist_clear(inst->popup_genlist);
236 
237    if (ctxt->error)
238      {
239         elm_object_text_set(inst->popup_title_entry, _("No information available"));
240         elm_object_text_set(inst->popup_error_label, ctxt->error);
241         if ((ctxt->v_maj != -1) && (ctxt->v_min != -1) && (ctxt->v_mic != -1))
242           {
243              snprintf(buf, sizeof(buf), "<ps/>PackageKit version: %d.%d.%d",
244                       ctxt->v_maj, ctxt->v_min, ctxt->v_mic);
245              elm_entry_entry_append(inst->popup_error_label, buf);
246           }
247         return;
248      }
249 
250    EINA_LIST_FOREACH(ctxt->packages, l, pkg)
251      {
252         if (rebuild_list)
253           elm_genlist_item_append(inst->popup_genlist, inst->popup_genlist_itc,
254                                   pkg, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
255         num_updates++;
256      }
257 
258    // show the progress bar if an operation is in progress
259    if (ctxt->transaction)
260      {
261         elm_genlist_clear(inst->popup_genlist);
262         elm_progressbar_value_set(inst->popup_progressbar,
263                                   ctxt->transaction_progress);
264         evas_object_show(inst->popup_progressbar_frame);
265      }
266    else
267      evas_object_hide(inst->popup_progressbar_frame);
268 
269    // update title and error lables
270    if (ctxt->transaction)
271       snprintf(buf, sizeof(buf), _("Operation in progress"));
272    else if (num_updates >= 1)
273      snprintf(buf, sizeof(buf), P_("One update available", "%d updates available", num_updates), num_updates);
274    else
275      snprintf(buf, sizeof(buf), _("Your system is updated"));
276    elm_object_text_set(inst->popup_title_entry, buf);
277    elm_object_text_set(inst->popup_error_label, "");
278 
279    // update the status of the install button
280    selected = elm_genlist_selected_items_get(inst->popup_genlist);
281    if (ctxt->transaction)
282      {
283         elm_object_text_set(inst->popup_install_button, _("Please wait"));
284         elm_object_disabled_set(inst->popup_install_button, EINA_TRUE);
285      }
286    else if (num_updates < 1)
287      {
288         elm_object_text_set(inst->popup_install_button, _("Nothing to do"));
289         elm_object_disabled_set(inst->popup_install_button, EINA_TRUE);
290      }
291    else if ((selected == NULL) || (eina_list_count(selected) == 0))
292      {
293         elm_object_text_set(inst->popup_install_button,
294                            _("Install all available updates"));
295         elm_object_disabled_set(inst->popup_install_button, EINA_FALSE);
296      }
297    else if (eina_list_count(selected) > 0)
298      {
299         snprintf(buf, sizeof(buf), P_("Install the selected update",
300                                       "Install %d selected updates",
301                                       eina_list_count(selected)),
302                                       eina_list_count(selected));
303         elm_object_text_set(inst->popup_install_button, buf);
304         elm_object_disabled_set(inst->popup_install_button, EINA_FALSE);
305      }
306 }
307 
308 void
packagekit_all_popups_update(E_PackageKit_Module_Context * ctxt,Eina_Bool rebuild_list)309 packagekit_all_popups_update(E_PackageKit_Module_Context *ctxt,
310                              Eina_Bool rebuild_list)
311 {
312    E_PackageKit_Instance *inst;
313    Eina_List *l;
314 
315    EINA_LIST_FOREACH(ctxt->instances, l, inst)
316      packagekit_popup_update(inst, rebuild_list);
317 }
318 
319 void
packagekit_progress_percentage_update(E_PackageKit_Module_Context * ctxt,int percent)320 packagekit_progress_percentage_update(E_PackageKit_Module_Context *ctxt,
321                                       int percent)
322 {
323    E_PackageKit_Instance *inst;
324    Eina_List *l;
325    double val = (double)percent / 100.0;
326 
327    ctxt->transaction_progress = val;
328    EINA_LIST_FOREACH(ctxt->instances, l, inst)
329      if (inst->popup_progressbar)
330        elm_progressbar_value_set(inst->popup_progressbar, val);
331 }
332 
333 static void
_popup_del_cb(void * obj)334 _popup_del_cb(void *obj)
335 {
336    packagekit_popup_del(e_object_data_get(obj));
337 }
338 
339 static char *
_gl_item_single_text_get(void * data,Evas_Object * obj EINA_UNUSED,const char * part)340 _gl_item_single_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
341 {
342    E_PackageKit_Package *pkg = data;
343 
344    if (!strcmp(part, "elm.text"))
345      {
346         char *s = malloc(strlen(pkg->name) + strlen(pkg->version) + 2);
347         sprintf(s, "%s %s", pkg->name, pkg->version);
348         return s;
349      }
350 
351    return NULL;
352 }
353 
354 static char *
_gl_item_double_text_get(void * data,Evas_Object * obj EINA_UNUSED,const char * part)355 _gl_item_double_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
356 {
357    E_PackageKit_Package *pkg = data;
358 
359    if (!strcmp(part, "elm.text"))
360      {
361         return strdup(pkg->summary);
362      }
363    else
364      {
365         char *s = malloc(strlen(pkg->name) + strlen(pkg->version) + 2);
366         sprintf(s, "%s %s", pkg->name, pkg->version);
367         return s;
368      }
369 
370    return NULL;
371 }
372 
373 static Evas_Object *
_gl_item_content_get(void * data,Evas_Object * obj,const char * part)374 _gl_item_content_get(void *data, Evas_Object *obj, const char *part)
375 {
376    E_PackageKit_Package *pkg = data;
377    Efreet_Desktop *desktop;
378    Evas_Object *icon;
379 
380    if (!strcmp(part, "elm.swallow.icon"))
381      {
382         // get the priority icon from the theme
383         const char *emblem_name;
384 
385         switch (pkg->info)
386           {
387              case PK_INFO_ENUM_LOW:
388                emblem_name = "e/modules/packagekit/icon/low"; break;
389              case PK_INFO_ENUM_ENHANCEMENT:
390                emblem_name = "e/modules/packagekit/icon/enhancement"; break;
391              case PK_INFO_ENUM_NORMAL:
392                emblem_name = "e/modules/packagekit/icon/normal"; break;
393              case PK_INFO_ENUM_BUGFIX:
394                emblem_name = "e/modules/packagekit/icon/bugfix"; break;
395              case PK_INFO_ENUM_IMPORTANT:
396                emblem_name = "e/modules/packagekit/icon/important"; break;
397              case PK_INFO_ENUM_SECURITY:
398                emblem_name = "e/modules/packagekit/icon/security"; break;
399              default:
400                emblem_name = NULL; break;
401           }
402         if (emblem_name)
403           {
404             icon = edje_object_add(evas_object_evas_get(obj));
405             e_theme_edje_object_set(icon, "base/theme/modules/packagekit", emblem_name);
406             return icon;
407           }
408      }
409    else if (!strcmp(part, "elm.swallow.end"))
410      {
411         // try to find a desktop file that match the executable or the name
412         desktop = efreet_util_desktop_exec_find(pkg->name);
413         if (!desktop)
414           desktop = efreet_util_desktop_name_find(pkg->name);
415 
416         if (desktop && desktop->icon)
417           {
418              icon = elm_icon_add(obj);
419              elm_icon_standard_set(icon, desktop->icon);
420              efreet_desktop_free(desktop);
421              return icon;
422           }
423      }
424 
425    return NULL;
426 }
427 
428 static void
_genlist_selunsel_cb(void * data,Evas_Object * obj EINA_UNUSED,void * event EINA_UNUSED)429 _genlist_selunsel_cb(void *data, Evas_Object *obj EINA_UNUSED,
430                      void *event EINA_UNUSED)
431 {
432    packagekit_popup_update(data, EINA_FALSE);
433 }
434 
435 static void
_ctxpopup_dismissed(void * data,Evas_Object * obj,void * info EINA_UNUSED)436 _ctxpopup_dismissed(void *data, Evas_Object *obj, void *info EINA_UNUSED)
437 {
438    E_PackageKit_Instance *inst = data;
439 
440    evas_object_del(obj);
441    inst->ctxpopup = NULL;
442 }
443 
444 void
packagekit_popup_new(E_PackageKit_Instance * inst,Eina_Bool is_gadcon)445 packagekit_popup_new(E_PackageKit_Instance *inst, Eina_Bool is_gadcon)
446 {
447    Evas_Object *table, *bt, *ic, *lb, *li, *pb, *fr, *bx, *size_rect;
448    const char *p;
449 
450    if (is_gadcon)
451      {
452         inst->popup = e_gadcon_popup_new(inst->gcc, EINA_FALSE);
453         table = elm_table_add(e_comp->elm);
454      }
455    else
456      {
457         inst->ctxpopup = elm_ctxpopup_add(e_comp->elm);
458         elm_object_style_set(inst->ctxpopup, "noblock");
459         evas_object_smart_callback_add(inst->ctxpopup, "dismissed",
460                                        _ctxpopup_dismissed, inst);
461         table = elm_table_add(inst->ctxpopup);
462      }
463    evas_object_show(table);
464 
465    // horiz box for title and buttons
466    bx = elm_box_add(table);
467    elm_box_horizontal_set(bx, EINA_TRUE);
468    evas_object_size_hint_expand_set(bx, EVAS_HINT_EXPAND, 0.0);
469    evas_object_size_hint_fill_set(bx, EVAS_HINT_FILL, 0.0);
470    elm_table_pack(table, bx, 0, 0, 1, 1);
471    evas_object_show(bx);
472 
473    // title label
474    lb = inst->popup_title_entry = elm_entry_add(table);
475    elm_entry_editable_set(lb, 0);
476    evas_object_size_hint_expand_set(lb, EVAS_HINT_EXPAND, 0.0);
477    evas_object_size_hint_align_set(lb, EVAS_HINT_FILL, 0.5);
478    elm_entry_text_style_user_push(lb, "DEFAULT='font_weight=Bold'");
479    elm_box_pack_end(bx, lb);
480    evas_object_show(lb);
481 
482    // refresh button
483    ic = elm_icon_add(table);
484    evas_object_size_hint_min_set(ic, 16 * elm_config_scale_get(),
485                                      16 * elm_config_scale_get());
486    elm_icon_standard_set(ic, "view-refresh");
487    bt = elm_button_add(table);
488    elm_object_content_set(bt, ic);
489    evas_object_smart_callback_add(bt, "clicked", _update_button_cb, inst);
490    elm_box_pack_end(bx, bt);
491    evas_object_show(bt);
492 
493    // help button
494    ic = elm_icon_add(table);
495    evas_object_size_hint_min_set(ic, 16 * elm_config_scale_get(),
496                                      16 * elm_config_scale_get());
497    elm_icon_standard_set(ic, "help-contents");
498    bt = elm_button_add(table);
499    elm_object_content_set(bt, ic);
500    evas_object_smart_callback_add(bt, "clicked", _help_button_cb, inst);
501    elm_box_pack_end(bx, bt);
502    evas_object_show(bt);
503 
504    // central area (sizer)
505    size_rect = evas_object_rectangle_add(evas_object_evas_get(table));
506    evas_object_size_hint_min_set(size_rect, 300 * elm_config_scale_get(),
507                                             300 * elm_config_scale_get());
508    elm_table_pack(table, size_rect, 0, 1, 1, 1);
509 
510    // central area (error label)
511    lb = inst->popup_error_label = elm_entry_add(table);
512    elm_entry_editable_set(lb, EINA_FALSE);
513    E_EXPAND(lb);
514    E_FILL(lb);
515    elm_table_pack(table, lb, 0, 1, 1, 1);
516    evas_object_show(lb);
517 
518    // central area (genlist)
519    inst->popup_genlist_itc = elm_genlist_item_class_new();
520    if (inst->ctxt->config->show_description)
521      {
522         inst->popup_genlist_itc->item_style = "double_label";
523         inst->popup_genlist_itc->func.text_get = _gl_item_double_text_get;
524      }
525    else
526      {
527         inst->popup_genlist_itc->item_style = "default";
528         inst->popup_genlist_itc->func.text_get = _gl_item_single_text_get;
529      }
530    inst->popup_genlist_itc->func.content_get = _gl_item_content_get;
531 
532    li = inst->popup_genlist = elm_genlist_add(table);
533    elm_genlist_homogeneous_set(li, EINA_TRUE);
534    elm_genlist_mode_set(li, ELM_LIST_COMPRESS);
535    elm_genlist_multi_select_set(li, EINA_TRUE);
536    E_EXPAND(li);
537    E_FILL(li);
538    evas_object_smart_callback_add(li, "selected", _genlist_selunsel_cb, inst);
539    evas_object_smart_callback_add(li, "unselected", _genlist_selunsel_cb, inst);
540    elm_table_pack(table, li, 0, 1, 1, 1);
541    evas_object_show(li);
542 
543    // central area (progress bar) (inside a padding frame)
544    fr = inst->popup_progressbar_frame = elm_frame_add(table);
545    elm_object_style_set(fr, "pad_large");
546    E_EXPAND(fr);
547    E_FILL(fr);
548    elm_table_pack(table, fr, 0, 1, 1, 1);
549    evas_object_show(fr);
550 
551    pb = inst->popup_progressbar = elm_progressbar_add(table);
552    E_EXPAND(pb);
553    E_FILL(pb);
554    elm_object_content_set(fr, pb);
555 
556    // install button
557    bt = inst->popup_install_button = elm_button_add(table);
558    evas_object_size_hint_fill_set(bt, EVAS_HINT_FILL, 0.0);
559    evas_object_smart_callback_add(bt, "clicked", _install_button_cb, inst);
560    elm_table_pack(table, bt, 0, 2, 1, 1);
561    evas_object_show(bt);
562 
563    // run package manager button (only if configured)
564    p = inst->ctxt->config->manager_command;
565    if (p && p[0])
566      {
567         bt = elm_button_add(table);
568         evas_object_size_hint_fill_set(bt, EVAS_HINT_FILL, 0.0);
569         elm_object_text_set(bt, _("Run the package manager"));
570         evas_object_smart_callback_add(bt, "clicked", _run_button_cb, inst);
571         elm_table_pack(table, bt, 0, 3, 1, 1);
572         evas_object_show(bt);
573      }
574 
575    // setup and show the popup
576    if (is_gadcon)
577      {
578         e_gadcon_popup_content_set(inst->popup, table);
579         e_object_data_set(E_OBJECT(inst->popup), inst);
580         E_OBJECT_DEL_SET(inst->popup, _popup_del_cb);
581         e_gadcon_popup_show(inst->popup);
582      }
583    else
584      {
585         elm_object_content_set(inst->ctxpopup, table);
586         e_gadget_util_ctxpopup_place(inst->gadget, inst->ctxpopup, NULL);
587         evas_object_show(inst->ctxpopup);
588      }
589 
590    // update the popup state and contents
591    packagekit_popup_update(inst, EINA_TRUE);
592 }
593 
594 void
packagekit_popup_del(E_PackageKit_Instance * inst)595 packagekit_popup_del(E_PackageKit_Instance *inst)
596 {
597    if (inst->popup)
598      E_FREE_FUNC(inst->popup, e_object_del);
599    if (inst->ctxpopup)
600      elm_ctxpopup_dismiss(inst->ctxpopup);
601 
602    inst->popup_genlist = inst->popup_title_entry = NULL;
603    inst->popup_progressbar = inst->popup_progressbar_frame = NULL;
604    if (inst->popup_genlist_itc)
605      {
606         elm_genlist_item_class_free(inst->popup_genlist_itc);
607         inst->popup_genlist_itc = NULL;
608      }
609 }
610 
611 static void
_store_error(E_PackageKit_Module_Context * ctxt,const char * err)612 _store_error(E_PackageKit_Module_Context *ctxt, const char *err)
613 {
614    ERR("PKGKIT: ERROR: %s", err);
615    if (ctxt->error)
616       eina_stringshare_replace(&ctxt->error, err);
617    else
618       ctxt->error = eina_stringshare_add(err);
619    packagekit_icon_update(ctxt, EINA_FALSE);
620    packagekit_all_popups_update(ctxt, EINA_FALSE);
621 }
622 
623 /* DBus PackageKit method calls */
624 
625 static void
null_cb(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)626 null_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
627 {
628    E_PackageKit_Module_Context *ctxt = data;
629    const char *error, *error_msg;
630 
631    if (eldbus_message_error_get(msg, &error, &error_msg))
632      _store_error(ctxt, error_msg);
633 }
634 
635 
636 /* RefreshCache(in'b'force) */
637 static void
_signal_repo_detail_cb(void * data,const Eldbus_Message * msg)638 _signal_repo_detail_cb(void *data, const Eldbus_Message *msg)
639 { /* RepoDetail ('s'repo_id, 's'description, 'b'enabled) */
640    E_PackageKit_Module_Context *ctxt = data;
641    const char *error, *error_msg, *repo_id, *desc;
642    Eina_Bool enabled;
643 
644    if (eldbus_message_error_get(msg, &error, &error_msg))
645      {
646         _store_error(ctxt, error_msg);
647         return;
648      }
649    if (!eldbus_message_arguments_get(msg, "ssb", &repo_id, &desc, &enabled))
650      {
651         _store_error(ctxt, "could not get arguments (ssb)");
652         return;
653      }
654    //DBG("PKGKIT: RepoDetail: (%d) %s [ %s ]", enabled, repo_id, desc);
655 }
656 
657 static void
_signal_cache_finished_cb(void * data,const Eldbus_Message * msg)658 _signal_cache_finished_cb(void *data, const Eldbus_Message *msg)
659 {  /* Finished ('u'exit, 'u'runtime) */
660    E_PackageKit_Module_Context *ctxt = data;
661    const char *error, *error_msg;
662 
663    //DBG("PKGKIT: Cache Finished CB");
664 
665    if (eldbus_message_error_get(msg, &error, &error_msg))
666      {
667         _store_error(ctxt, error_msg);
668         return;
669      }
670 
671    Eldbus_Object *obj = eldbus_proxy_object_get(ctxt->transaction);
672    E_FREE_FUNC(ctxt->transaction, eldbus_proxy_unref);
673    E_FREE_FUNC(obj, eldbus_object_unref);
674 
675    packagekit_create_transaction_and_exec(ctxt, packagekit_get_updates);
676 }
677 
678 void
packagekit_refresh_cache(E_PackageKit_Module_Context * ctxt,const char * transaction)679 packagekit_refresh_cache(E_PackageKit_Module_Context *ctxt, const char *transaction)
680 {
681    Eldbus_Object *obj;
682    Eldbus_Proxy *proxy;
683    Eldbus_Pending *pending;
684 
685    ctxt->config->last_update = ecore_time_unix_get();
686 
687    obj = eldbus_object_get(ctxt->conn, "org.freedesktop.PackageKit", transaction);
688    proxy = eldbus_proxy_get(obj, "org.freedesktop.PackageKit.Transaction");
689    pending = eldbus_proxy_call(proxy, "RefreshCache", null_cb, ctxt, -1, "b", 1);
690    if (!pending)
691      {
692         _store_error(ctxt, "could not call RefreshCache()");
693         return;
694      }
695    eldbus_proxy_signal_handler_add(proxy, "Finished",
696                                    _signal_cache_finished_cb, ctxt);
697    eldbus_proxy_signal_handler_add(proxy, "RepoDetail",
698                                    _signal_repo_detail_cb, ctxt);
699    ctxt->transaction = proxy;
700 }
701 
702 
703 /* GetUpdates(in't'filter) */
704 static void
_signal_package_cb(void * data,const Eldbus_Message * msg)705 _signal_package_cb(void *data, const Eldbus_Message *msg)
706 {  /* Package ('u'info, 's'package_id, 's'summary) */
707    const char *error, *error_msg, *pkg_id, *summary, *info_str;
708    E_PackageKit_Module_Context *ctxt = data;
709    PackageKit_Package_Info info;
710    unsigned num_elements = 0;
711    char **splitted;
712    Eina_Bool ret;
713 
714    if (eldbus_message_error_get(msg, &error, &error_msg))
715      {
716         _store_error(ctxt, error_msg);
717         return;
718      }
719    if (PKITV07)
720      ret = eldbus_message_arguments_get(msg, "sss", &info_str, &pkg_id, &summary);
721    else
722      ret = eldbus_message_arguments_get(msg, "uss", &info, &pkg_id, &summary);
723    if (!ret)
724      {
725         _store_error(ctxt, "could not get package arguments");
726         return;
727      }
728    //if (PKITV07)
729      //{ DBG("PKGKIT: Package: (%s) %s [ %s ]", info_str, pkg_id, summary); }
730    //else
731      //{ DBG("PKGKIT: Package: (%d) %s [ %s ]", info, pkg_id, summary); }
732 
733    splitted = eina_str_split_full(pkg_id, ";", 3, &num_elements);
734    if (num_elements >= 2)
735      {
736         E_PackageKit_Package *pkg = E_NEW(E_PackageKit_Package, 1);
737         pkg->pkg_id = eina_stringshare_add(pkg_id);
738         pkg->name = eina_stringshare_add(splitted[0]);
739         pkg->version = eina_stringshare_add(splitted[1]);
740         pkg->summary = eina_stringshare_add(summary);
741         if (PKITV07)
742           {
743              if (!info_str) pkg->info = PK_INFO_ENUM_NORMAL;
744              else if (!strcmp(info_str, "normal"))      pkg->info = PK_INFO_ENUM_NORMAL;
745              else if (!strcmp(info_str, "security"))    pkg->info = PK_INFO_ENUM_SECURITY;
746              else if (!strcmp(info_str, "blocked"))     pkg->info = PK_INFO_ENUM_BLOCKED;
747              else if (!strcmp(info_str, "low"))         pkg->info = PK_INFO_ENUM_LOW;
748              else if (!strcmp(info_str, "enhancement")) pkg->info = PK_INFO_ENUM_ENHANCEMENT;
749              else if (!strcmp(info_str, "bugfix"))      pkg->info = PK_INFO_ENUM_BUGFIX;
750              else if (!strcmp(info_str, "important"))   pkg->info = PK_INFO_ENUM_IMPORTANT;
751              else pkg->info = PK_INFO_ENUM_UNKNOWN;
752           }
753         else
754           pkg->info = info;
755         ctxt->packages = eina_list_append(ctxt->packages, pkg);
756      }
757    if (splitted)
758      {
759         free(splitted[0]);
760         free(splitted);
761      }
762 }
763 
764 static void
_signal_finished_cb(void * data,const Eldbus_Message * msg)765 _signal_finished_cb(void *data, const Eldbus_Message *msg)
766 {  /* Finished ('u'exit, 'u'runtime) */
767    const char *error, *error_msg;
768    E_PackageKit_Module_Context *ctxt = data;
769 
770    if (eldbus_message_error_get(msg, &error, &error_msg))
771      {
772         _store_error(ctxt, error_msg);
773         return;
774      }
775 
776    Eldbus_Object *obj = eldbus_proxy_object_get(ctxt->transaction);
777    E_FREE_FUNC(ctxt->transaction, eldbus_proxy_unref);
778    E_FREE_FUNC(obj, eldbus_object_unref);
779    E_FREE_FUNC(ctxt->error, eina_stringshare_del);
780 
781    //DBG("PKGKIT: PackageFinished");
782    packagekit_icon_update(ctxt, EINA_FALSE);
783    packagekit_all_popups_update(ctxt, EINA_TRUE);
784 }
785 
786 void
packagekit_get_updates(E_PackageKit_Module_Context * ctxt,const char * transaction)787 packagekit_get_updates(E_PackageKit_Module_Context *ctxt, const char *transaction)
788 {
789    Eldbus_Object *obj;
790    Eldbus_Proxy *proxy;
791    Eldbus_Pending *pending;
792    E_PackageKit_Package *pkg;
793 
794    obj = eldbus_object_get(ctxt->conn, "org.freedesktop.PackageKit", transaction);
795    proxy = eldbus_proxy_get(obj, "org.freedesktop.PackageKit.Transaction");
796    if (PKITV07)
797      pending = eldbus_proxy_call(proxy, "GetUpdates", null_cb, ctxt, -1, "s", "none");
798    else
799      pending = eldbus_proxy_call(proxy, "GetUpdates", null_cb, ctxt, -1, "t", 1);
800    if (!pending)
801      {
802         _store_error(ctxt, "could not call GetUpdates()");
803         return;
804      }
805 
806    eldbus_proxy_signal_handler_add(proxy, "Package", _signal_package_cb, ctxt);
807    eldbus_proxy_signal_handler_add(proxy, "Finished", _signal_finished_cb, ctxt);
808    ctxt->transaction = proxy;
809 
810    EINA_LIST_FREE(ctxt->packages, pkg)
811      {
812         E_FREE_FUNC(pkg->pkg_id, eina_stringshare_del);
813         E_FREE_FUNC(pkg->name, eina_stringshare_del);
814         E_FREE_FUNC(pkg->version, eina_stringshare_del);
815         E_FREE_FUNC(pkg->summary, eina_stringshare_del);
816      }
817 }
818 
819 
820 /* UpdatePackages(in't'transaction_flags, in'as'package_ids) */
821 static void
_signal_update_error_code_cb(void * data,const Eldbus_Message * msg)822 _signal_update_error_code_cb(void *data, const Eldbus_Message *msg)
823 {  /* ErrorCode ('u'code, 's'details) */
824    const char *error, *error_msg, *details;
825    E_PackageKit_Module_Context *ctxt = data;
826    Eina_Bool ret;
827    int err_code;
828 
829    if (eldbus_message_error_get(msg, &error, &error_msg))
830      {
831         _store_error(ctxt, error_msg);
832         return;
833      }
834 
835    ret = eldbus_message_arguments_get(msg, "us", &err_code, &details);
836    if (!ret)
837      {
838         _store_error(ctxt, "could not get error code arguments");
839         return;
840      }
841 
842    if (details)
843      _store_error(ctxt, details);
844 }
845 
846 static void
_signal_update_finished_cb(void * data,const Eldbus_Message * msg)847 _signal_update_finished_cb(void *data, const Eldbus_Message *msg)
848 {  /* Finished ('u'exit, 'u'runtime) */
849    const char *error, *error_msg;
850    E_PackageKit_Module_Context *ctxt = data;
851 
852    if (eldbus_message_error_get(msg, &error, &error_msg))
853      _store_error(ctxt, error_msg);
854    else
855      E_FREE_FUNC(ctxt->error, eina_stringshare_del);
856 
857    Eldbus_Object *obj = eldbus_proxy_object_get(ctxt->transaction);
858    E_FREE_FUNC(ctxt->transaction, eldbus_proxy_unref);
859    E_FREE_FUNC(obj, eldbus_object_unref);
860 }
861 
862 void
packagekit_update_packages(E_PackageKit_Module_Context * ctxt,const char * transaction)863 packagekit_update_packages(E_PackageKit_Module_Context *ctxt, const char *transaction)
864 {
865    Eldbus_Object *obj;
866    Eldbus_Proxy *proxy;
867    Eldbus_Message *msg;
868    Eldbus_Message_Iter *iter, *array_of_string;
869    Eldbus_Pending *pending;
870    E_PackageKit_Package *pkg;
871    Eina_List *l;
872 
873    fprintf(stderr, "PKIT: UpdatePackages (t:%s)\n", transaction);
874 
875    obj = eldbus_object_get(ctxt->conn, "org.freedesktop.PackageKit", transaction);
876    proxy = eldbus_proxy_get(obj, "org.freedesktop.PackageKit.Transaction");
877    msg = eldbus_proxy_method_call_new(proxy, "UpdatePackages");
878    iter = eldbus_message_iter_get(msg);
879    eldbus_message_iter_arguments_append(iter, "tas",
880                                         PK_TRANSACTION_FLAG_ENUM_ONLY_TRUSTED,
881                                         &array_of_string);
882    EINA_LIST_FOREACH(ctxt->packages, l, pkg)
883      {
884         if (pkg->to_be_installed)
885           {
886              DBG("Install: %s %s", pkg->pkg_id, pkg->version);
887              eldbus_message_iter_arguments_append(array_of_string, "s", pkg->pkg_id);
888           }
889      }
890    eldbus_message_iter_container_close(iter, array_of_string);
891 
892    pending = eldbus_proxy_send(proxy, msg, null_cb, ctxt, -1);
893    if (!pending)
894      {
895         _store_error(ctxt, "could not call UpdatePackages()");
896         return;
897      }
898    eldbus_proxy_signal_handler_add(proxy, "ErrorCode",
899                                    _signal_update_error_code_cb, ctxt);
900    eldbus_proxy_signal_handler_add(proxy, "Finished",
901                                    _signal_update_finished_cb, ctxt);
902    ctxt->transaction = proxy;
903 }
904 
905 /* CreateTransaction() */
906 static void
_transaction_changed_props_iter(void * data,const void * key,Eldbus_Message_Iter * val)907 _transaction_changed_props_iter(void *data, const void *key,
908                                 Eldbus_Message_Iter *val)
909 {
910    E_PackageKit_Module_Context *ctxt = data;
911 
912    if (!strcmp(key, "Percentage"))
913      {
914         int val_int;
915         eldbus_message_iter_basic_get(val, &val_int);
916         packagekit_progress_percentage_update(ctxt, val_int);
917      }
918 }
919 
920 static void
_signal_transaction_props_changed_cb(void * data,const Eldbus_Message * msg)921 _signal_transaction_props_changed_cb(void *data, const Eldbus_Message *msg)
922 { /* PropertiesChanged('s'interface_name, 'a{sv}'changed_properties,
923                        'as' invalidated_properties) */
924    E_PackageKit_Module_Context *ctxt = data;
925    const char *error, *error_msg, *interface_name;
926    Eldbus_Message_Iter *changed_properties, *invalidated_properties;
927    Eina_Bool ret;
928 
929    if (eldbus_message_error_get(msg, &error, &error_msg))
930      {
931         _store_error(ctxt, error_msg);
932         return;
933      }
934 
935    ret = eldbus_message_arguments_get(msg, "sa{sv}as", &interface_name,
936                                       &changed_properties,
937                                       &invalidated_properties);
938    if (!ret)
939      {
940         _store_error(ctxt, "could not get signal arguments");
941         return;
942      }
943 
944    eldbus_message_iter_dict_iterate(changed_properties, "sv",
945                                     _transaction_changed_props_iter, ctxt);
946 }
947 
948 static void
_transaction_created_cb(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending)949 _transaction_created_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
950 {
951    const char *error, *error_msg, *trans_path;
952    E_PackageKit_Module_Context *ctxt = data;
953    E_PackageKit_Transaction_Func func;
954    Eldbus_Proxy *proxy;
955    Eldbus_Object *obj;
956    Eina_Bool ret;
957 
958    if (eldbus_message_error_get(msg, &error, &error_msg))
959      {
960         _store_error(ctxt, error_msg);
961         return;
962      }
963 
964    if (PKITV07)
965      ret = eldbus_message_arguments_get(msg, "s", &trans_path);
966    else
967      ret = eldbus_message_arguments_get(msg, "o", &trans_path);
968    if (!ret)
969      {
970         _store_error(ctxt, "could not get transaction path");
971         return;
972      }
973 
974    // monitor the "Percentage" property to update the progress bar
975    obj = eldbus_object_get(ctxt->conn, "org.freedesktop.PackageKit", trans_path);
976    proxy = eldbus_proxy_get(obj, "org.freedesktop.DBus.Properties");
977    eldbus_proxy_signal_handler_add(proxy, "PropertiesChanged",
978                                    _signal_transaction_props_changed_cb, ctxt);
979 
980    // call the operation function
981    func = eldbus_pending_data_get(pending, "func");
982    func(ctxt, trans_path);
983 
984    // update all the faces
985    packagekit_icon_update(ctxt, EINA_TRUE);
986    packagekit_all_popups_update(ctxt, EINA_FALSE);
987 }
988 
989 void
packagekit_create_transaction_and_exec(E_PackageKit_Module_Context * ctxt,E_PackageKit_Transaction_Func func)990 packagekit_create_transaction_and_exec(E_PackageKit_Module_Context *ctxt,
991                                        E_PackageKit_Transaction_Func func)
992 {
993    Eldbus_Pending *pending;
994 
995    //DBG("PKGKIT: Version: %d.%d.%d", ctxt->v_maj, ctxt->v_min, ctxt->v_mic);
996 
997    if (ctxt->transaction)
998      {
999         WRN("PKGKIT: Another transaction in progress...");
1000         return;
1001      }
1002 
1003    pending = eldbus_proxy_call(ctxt->packagekit,
1004                                PKITV07 ? "GetTid" : "CreateTransaction",
1005                                _transaction_created_cb, ctxt, -1, "");
1006    if (!pending)
1007      {
1008         _store_error(ctxt, "could not call CreateTransaction()");
1009         return;
1010      }
1011    eldbus_pending_data_set(pending, "func", func);
1012 }
1013 
1014 
1015 /* PackageKit DBus */
1016 static void
_signal_updates_changed_cb(void * data,const Eldbus_Message * msg EINA_UNUSED)1017 _signal_updates_changed_cb(void *data, const Eldbus_Message *msg EINA_UNUSED)
1018 {
1019    E_PackageKit_Module_Context *ctxt = data;
1020 
1021    packagekit_create_transaction_and_exec(ctxt, packagekit_get_updates);
1022 }
1023 
1024 static void
_iterate_dict(void * data,const void * key,Eldbus_Message_Iter * var)1025 _iterate_dict(void *data, const void *key, Eldbus_Message_Iter *var)
1026 {
1027    E_PackageKit_Module_Context *ctxt = data;
1028 
1029    if (!strcmp(key, "VersionMajor"))
1030      eldbus_message_iter_arguments_get(var, "u", &(ctxt->v_maj));
1031    else if (!strcmp(key, "VersionMinor"))
1032      eldbus_message_iter_arguments_get(var, "u", &(ctxt->v_min));
1033    else if (!strcmp(key, "VersionMicro"))
1034      eldbus_message_iter_arguments_get(var, "u", &(ctxt->v_mic));
1035    else return;
1036 
1037    if ((ctxt->v_maj != -1) && (ctxt->v_min != -1) && (ctxt->v_mic != -1))
1038      packagekit_create_transaction_and_exec(ctxt, packagekit_get_updates);
1039 }
1040 
1041 static void
_prop_get_cb(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)1042 _prop_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
1043 {
1044    E_PackageKit_Module_Context *ctxt = data;
1045    Eldbus_Message_Iter *array;
1046    const char *error, *error_msg;
1047 
1048    if (eldbus_message_error_get(msg, &error, &error_msg))
1049      {
1050         _store_error(ctxt, error_msg);
1051         return;
1052      }
1053    if (!eldbus_message_arguments_get(msg, "a{sv}", &array))
1054      {
1055         _store_error(ctxt, "could not get arguments (a{sv})");
1056         return;
1057      }
1058    eldbus_message_iter_dict_iterate(array, "sv", _iterate_dict, ctxt);
1059 }
1060 
1061 Eina_Bool
packagekit_dbus_connect(E_PackageKit_Module_Context * ctxt)1062 packagekit_dbus_connect(E_PackageKit_Module_Context *ctxt)
1063 {
1064    Eldbus_Object *obj;
1065 
1066    //DBG("PKGKIT: dbus_init()");
1067 
1068    ctxt->conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
1069    if (!ctxt->conn)
1070      {
1071         _store_error(ctxt, "could not connect to system bus");
1072         return EINA_FALSE;
1073      }
1074 
1075    obj = eldbus_object_get(ctxt->conn, "org.freedesktop.PackageKit",
1076                                        "/org/freedesktop/PackageKit");
1077    ctxt->packagekit = eldbus_proxy_get(obj, "org.freedesktop.PackageKit");
1078    if (!ctxt->packagekit)
1079    {
1080       _store_error(ctxt, "could not connect to PackageKit");
1081       return EINA_FALSE;
1082    }
1083 
1084    eldbus_proxy_property_get_all(ctxt->packagekit, _prop_get_cb, ctxt);
1085    eldbus_proxy_signal_handler_add(ctxt->packagekit, "UpdatesChanged",
1086                                    _signal_updates_changed_cb, ctxt);
1087 
1088    return EINA_TRUE;
1089 }
1090 
1091 void
packagekit_dbus_disconnect(E_PackageKit_Module_Context * ctxt)1092 packagekit_dbus_disconnect(E_PackageKit_Module_Context *ctxt)
1093 {
1094    Eldbus_Object *obj;
1095 
1096    //DBG("PKGKIT: dbus_shutdown()");
1097 
1098    if (ctxt->transaction)
1099      {
1100         // TODO abort the transaction ???
1101         obj = eldbus_proxy_object_get(ctxt->transaction);
1102         E_FREE_FUNC(ctxt->transaction, eldbus_proxy_unref);
1103         E_FREE_FUNC(obj, eldbus_object_unref);
1104      }
1105 
1106    obj = eldbus_proxy_object_get(ctxt->packagekit);
1107    E_FREE_FUNC(ctxt->packagekit, eldbus_proxy_unref);
1108    E_FREE_FUNC(obj, eldbus_object_unref);
1109 
1110    eldbus_connection_unref(ctxt->conn);
1111 }
1112