~ubuntu-core-dev/update-notifier/ubuntu

« back to all changes in this revision

Viewing changes to src/hooks.c

  • Committer: mvo
  • Date: 2005-02-03 12:45:41 UTC
  • Revision ID: gustavo@niemeyer.net-20050203124541-66b00f59dd8cee24
* src/rfc822.h: added a comment explaining about the memory use
* src/hooks.c: basic i18n support added, needs more love

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#ifdef HAVE_CONFIG_H
2
 
#include "config.h"
3
 
#endif
4
1
 
 
2
#include "hooks.h"
 
3
#include "rfc822.h"
 
4
#include "assert.h"
5
5
#include <glib.h>
6
 
#include <gtk/gtk.h>
7
6
#include <glib/gstdio.h>
8
 
#include <glade/glade.h>   
9
 
 
10
7
#include <locale.h>
11
8
 
12
 
#include "update-notifier.h"
13
 
#include "hooks.h"
14
 
#include "rfc822.h"
15
 
#include "assert.h"
16
 
#include "md5.h"
17
 
 
18
9
/* relative to the home dir */
19
10
#define HOOKS_SEEN ".update-notifier/hooks_seen"
20
11
 
21
 
/* used by e.g. the installer to mark stuff that's already done */
22
 
#define GLOBAL_HOOKS_SEEN "/etc/update-notifier/hooks_seen"
23
 
 
24
 
#define HOOK_DEBUG 0
25
 
 
26
 
 
27
 
// Debuging 
28
 
static void debug_log_handler (const gchar   *log_domain,
29
 
                               GLogLevelFlags log_level,
30
 
                               const gchar   *message,
31
 
                               gpointer       user_data)
32
 
{
33
 
#if HOOK_DEBUG 
34
 
    g_log_default_handler (log_domain, log_level, message, user_data);
35
 
#endif
36
 
}
37
 
 
38
 
 
39
12
void hooks_trayicon_update_tooltip (TrayApplet *un, int num_hooks)
40
13
{
41
 
   g_debug("update_tooltip: %x ", un);
 
14
   //g_print("update_tooltip: %x \n", un);
42
15
   gchar *updates;
43
16
   gchar *explanation;
44
17
 
45
 
   updates = g_strdup_printf(ngettext("There is %i item of post-update information available!", "There are %i items of post-update information available!", num_hooks),  num_hooks);
46
 
   explanation = ngettext("Press this icon to show the information.", "Press this icon to show the information.", num_hooks);
 
18
   updates = g_strdup_printf(_("There are %i post-update informations available!"), 
 
19
                             num_hooks);
 
20
   
 
21
   explanation = _("Press this icon to show the information.");
47
22
 
48
23
   gtk_tooltips_set_tip(GTK_TOOLTIPS(un->tooltip), 
49
24
                        GTK_WIDGET (un->eventbox), 
52
27
   g_free (updates);
53
28
}
54
29
 
55
 
 
56
 
// compare a HookFile with a filename and find the HookFile that matches
57
30
gint compare_hook_func(gconstpointer a, gconstpointer b)
58
31
{
59
 
   //g_debug("compare: %s %s\n",(char*)(((HookFileSeen*)a)->filename),(char*)b);
60
 
   g_assert(a);
61
 
   g_assert(b);
62
 
 
63
 
   return strcmp(((HookFile*)a)->filename, b);
64
 
}
65
 
 
66
 
// return the most recent mtime or ctime of the file
67
 
time_t hook_file_time(const gchar *filename)
68
 
{
 
32
   //g_print("compare: %s %s\n",(char*)(((HookFileSeen*)a)->filename),(char*)b);
 
33
   return strcmp(((HookFileSeen*)a)->filename, b);
 
34
}
 
35
 
 
36
gboolean hook_file_is_new(HookDialog *h, const gchar *filename)
 
37
{
 
38
   if(g_list_find_custom(h->hook_files_seen, 
 
39
                         filename, compare_hook_func) == NULL)
 
40
      return TRUE;
 
41
   else 
 
42
      return FALSE;
 
43
}
 
44
 
 
45
gboolean hook_file_mark_as_seen(HookDialog *hook_dialog, 
 
46
                                const gchar *hook_file)
 
47
{
 
48
   //g_print("mark_hook_file_as_seen: %s\n",hook_file);
 
49
 
 
50
   gchar *filename = g_strdup_printf("%s/"HOOKS_SEEN,g_get_home_dir());
 
51
   FILE *f = fopen(filename, "a");
 
52
   if(f==NULL)
 
53
      return FALSE;
 
54
 
69
55
   struct stat buf;
70
 
   char *file = g_strdup_printf("%s/%s",HOOKS_DIR, filename);
71
 
   if(g_stat(file, &buf) <0) {
72
 
      g_error("can't stat %s\n",file);
73
 
      g_free(file);
74
 
      return 0;
75
 
   }
76
 
   g_free(file);
77
 
 
78
 
   time_t mtime = buf.st_mtime;
79
 
   time_t ctime = buf.st_ctime;
80
 
 
81
 
   return mtime > ctime ? mtime : ctime;
82
 
}
83
 
 
84
 
gboolean hook_file_md5(const gchar *filename, char *md5)
85
 
{
86
 
   char buf[512];
87
 
   FILE *f;
88
 
   char *file;
89
 
   int n;
90
 
   md5_context md5ctx;
91
 
 
92
 
   file = g_strdup_printf("%s/%s",HOOKS_DIR, filename);
93
 
   f = fopen(file,"r");
94
 
   if(f == NULL) {
95
 
      g_warning("can't read %s\n",file);
96
 
      g_free(file);
97
 
      return FALSE;
98
 
   }
99
 
   md5_starts(&md5ctx);
100
 
   do {
101
 
      n = fread(buf,1, sizeof(buf), f);
102
 
      md5_update(&md5ctx, buf,n);
103
 
   } while(n > 0);
104
 
   md5_finish(&md5ctx, md5);
105
 
 
106
 
   g_free(file);
107
 
   return TRUE;
108
 
}
109
 
 
110
 
/* mark a given hook file as seen 
111
 
  (actually implemented to write out all the information we have)
112
 
*/
113
 
gboolean hook_file_mark_as_seen(HookDialog *hook_dialog, 
114
 
                                HookFile *hf)
115
 
{
116
 
   g_debug("mark_hook_file_as_seen: %s", hf->filename);
117
 
 
118
 
   // copy the md5
119
 
   char md5[16];
120
 
   hook_file_md5(hf->filename,&md5);
121
 
 
122
 
   // mark as seen 
123
 
   hf->seen = TRUE;
124
 
 
125
 
   // update the time (extra paranoia, shouldn't be needed)
126
 
   hf->mtime = hook_file_time(hf->filename);
127
 
 
128
 
   // write out the list of known files
129
 
   gchar *filename = g_strdup_printf("%s/%s",g_get_home_dir(),HOOKS_SEEN);
130
 
   FILE *f = fopen(filename, "w");
131
 
   if(f==NULL) {
132
 
      g_warning("Something went wrong writing the users hook file");
133
 
      return FALSE;
134
 
   }
135
 
 
136
 
   // write out all the hooks that are seen 
137
 
   //
138
 
   // and any hooks that are not yet seen but have the same md5sum 
139
 
   // as the one just marked (avoids showing duplicated hooks effecivly). 
140
 
   //
141
 
   // For hooks with the same md5sum use the mtime of the just displayed hook
142
 
   GList *elm = g_list_first(hook_dialog->hook_files);
143
 
   for(;elm != NULL; elm = g_list_next(elm)) {
144
 
      HookFile *e = (HookFile*)elm->data;
145
 
      g_debug("looking at: %s (%s)",e->filename, e->md5);
146
 
      if(e->seen == TRUE) {
147
 
         g_debug("e->seen: %s %i %x", e->filename,e->mtime, (int)(e->cmd_run));
148
 
         fprintf(f,"%s %i %x\n", e->filename, e->mtime, (int)(e->cmd_run));
149
 
      } else if(memcmp(e->md5,md5,16) == 0) {
150
 
         e->seen = TRUE;
151
 
         fprintf(f,"%s %i %x\n", e->filename,hf->mtime, (int)(e->cmd_run));
152
 
         g_debug("same md5: %s %i %x",e->filename,hf->mtime,(int)(e->cmd_run));
153
 
      }
154
 
   }
 
56
   gchar *file = g_strdup_printf("%s%s",HOOKS_DIR,hook_file);
 
57
   g_stat(file, &buf);
 
58
 
 
59
   HookFileSeen *t = g_new0(HookFileSeen,1);
 
60
   t->filename = g_strdup(hook_file);
 
61
   t->mtime = buf.st_mtime;
 
62
   t->cmd_run = 0;
 
63
   fprintf(f,"%s %i %x\n", t->filename, t->mtime, (int)(t->cmd_run));
155
64
 
156
65
   fclose(f);
157
66
   g_free(filename);
158
67
 
 
68
   hook_dialog->hook_files_seen= g_list_append(hook_dialog->hook_files_seen,t);
 
69
 
159
70
   return TRUE;
160
71
}
161
72
 
162
 
/* mark a given HookFile as run */
163
 
gboolean mark_hook_file_as_run(HookDialog *hook_dialog, HookFile *hf)
 
73
gboolean mark_hook_file_as_run(HookDialog *hook_dialog, const gchar *filename)
164
74
{
165
 
   if(hf == NULL)
166
 
      return FALSE;
167
 
 
168
 
   g_debug("mark_hook_file_as_run: %s\n",hf->filename);
169
 
   hf->cmd_run = TRUE;
170
 
 
 
75
   // IMPLEMENT ME
 
76
   //g_print("mark_hook_file_as_run: %s\n",filename);
171
77
   return TRUE;
172
78
}
173
79
 
204
110
   /* try $field-$languagecode_$countrycode first */
205
111
   s = g_strdup_printf("%s-%s", field, get_lang_code(FALSE));
206
112
   entry = rfc822_header_lookup(rfc822, s);
207
 
   //g_debug("Looking for: %s ; found: %s\n",s,entry);
 
113
   //g_print("Looking for: %s ; found: %s\n",s,entry);
208
114
   g_free(s);
209
115
   if(entry != NULL)
210
116
      return entry;
211
117
 
212
118
   /* try $field-$languagecode next */
213
119
   s = g_strdup_printf("%s-%s", field, get_lang_code(TRUE));
214
 
   //g_debug("Looking for: %s ; found: %s\n",s,entry);
 
120
   //g_print("Looking for: %s ; found: %s\n",s,entry);
215
121
   entry = rfc822_header_lookup(rfc822, s);
216
122
   g_free(s);
217
123
   if(entry != NULL)
218
124
      return entry;
219
125
 
220
 
   /* now try translating it with gettext */
221
 
   entry = rfc822_header_lookup(rfc822, field);
222
 
   return entry;
223
 
}
224
 
 
225
 
char* hook_description_get_summary(struct rfc822_header *rfc822)
226
 
{
227
 
   char *description = hook_file_lookup_i18n(rfc822, "Name");
228
 
 
229
 
   char *summary = g_strdup(description);
230
 
   char *p = strchr(summary,'\n');
231
 
   if(p != NULL)
232
 
      *p = 0;
233
 
   return summary;
234
 
}
235
 
 
236
 
char* hook_description_get_description(struct rfc822_header *rfc822)
237
 
{
238
 
   char *description = hook_file_lookup_i18n(rfc822, "Description");
239
 
   char *newd, *p;
240
 
 
241
 
   // look for the first \n, that's the summary
242
 
   newd = p = g_strdup(description);
243
 
   if(p == NULL)
244
 
      return "";
245
 
 
246
 
   // convert \n to ' '
247
 
   while( (p=strchr(p,'\n')) != NULL) 
248
 
          *p = ' ';
249
 
   // strip leading/trailing whitespace
250
 
   g_strstrip(newd);
251
 
 
252
 
   // return the rest
253
 
   return newd;
 
126
   /* if everything else fails ... return untranslated */
 
127
   return rfc822_header_lookup(rfc822, field);
254
128
}
255
129
 
256
130
/*
257
131
 * show the given hook file
258
132
 */
259
 
gboolean show_next_hook(TrayApplet *ta, GList *hooks)
 
133
void show_one_hook(TrayApplet *ta, gchar *hook_file)
260
134
{
261
 
   //g_debug("show_next_hook()\n");
262
 
 
263
135
   HookDialog *hook_dialog = (HookDialog *)ta->user_data;
264
136
   GladeXML *xml = hook_dialog->glade_xml;
265
137
 
270
142
   GtkWidget *button_run = glade_xml_get_widget(xml, "button_run");
271
143
   assert(button_run);
272
144
 
273
 
   // init some vars
274
 
   HookFile *hf = NULL;
275
 
   char *hook_file = NULL;
276
 
 
277
 
   // find the next unseen hook
278
 
   GList *elm = g_list_first(hooks);
279
 
   for(;elm != NULL; elm = g_list_next(elm)) {
280
 
      hf = (HookFile*)elm->data;
281
 
      if(hf->seen == FALSE) {
282
 
         hook_file = hf->filename;
283
 
         //g_debug("next_hook is: %s\n",hook_file);
284
 
         break;
285
 
      }
286
 
   }
287
 
 
288
 
   if(hook_file == NULL) {
289
 
      g_debug("no unseen hookfile found in hook list of len (%i) \n",
290
 
              g_list_length(hooks));
291
 
      return FALSE;
292
 
   }
293
 
 
294
145
   char *filename = g_strdup_printf("%s%s",HOOKS_DIR,hook_file);
295
146
 
296
147
   /* setup the message */
299
150
   if(f == NULL) {
300
151
      g_critical("can't open %s", filename);
301
152
      g_free(filename);
302
 
      return FALSE;
 
153
      return;
303
154
   }
304
155
   struct rfc822_header *rfc822 = rfc822_parse_stanza(f);
305
156
 
307
158
   char *term = g_strstrip(rfc822_header_lookup(rfc822, "Terminal"));
308
159
   g_object_set_data(G_OBJECT(button_run),"cmd", g_strdup(cmd));
309
160
   g_object_set_data(G_OBJECT(button_run),"term", g_strdup(term));
310
 
   g_object_set_data(G_OBJECT(button_run),"hook_file", hf);
 
161
   g_object_set_data(G_OBJECT(button_run),"hook_file", g_strdup(hook_file));
311
162
   if(cmd != NULL) {
312
163
      gtk_widget_show(button_run);
313
164
   } else {
314
165
      gtk_widget_hide(button_run);
315
166
   }
316
167
 
317
 
   char *summary = hook_description_get_summary(rfc822);
318
 
   char *descr = hook_description_get_description(rfc822);
319
 
   char *s = g_strdup_printf("%s\n\n%s\n",gettext(summary), gettext(descr));
 
168
   char *name = hook_file_lookup_i18n(rfc822, "Name");
 
169
   char *description = hook_file_lookup_i18n(rfc822, "Description");
 
170
   char *s = g_strdup_printf("%s\n\n%s\n",name, description);
320
171
   gtk_text_buffer_set_text(buf, s, -1);
321
172
 
322
 
   // set the name to bold
323
 
   GtkTextIter start, end;
324
 
   gtk_text_buffer_get_iter_at_offset(buf, &start, 0);
325
 
   gtk_text_buffer_get_iter_at_offset(buf, &end, g_utf8_strlen(gettext(summary),-1));
326
 
   gtk_text_buffer_apply_tag_by_name(buf, "bold_tag", &start, &end);
327
 
 
328
 
   // clean up
329
173
   fclose(f);
 
174
   g_free(s);
330
175
   g_free(filename);
331
 
   g_free(s);
332
 
   g_free(summary);
333
 
   g_free(descr);
334
176
   rfc822_header_free_all(rfc822);
335
177
 
336
178
   /* mark the current hook file as seen */
337
 
   g_object_set_data(G_OBJECT(button_next), "HookFile", hf);
338
 
 
339
 
   return TRUE;
 
179
   hook_file_mark_as_seen(hook_dialog, hook_file);
 
180
   check_update_hooks(ta);
340
181
}
341
182
 
342
183
 
343
184
void cb_button_run(GtkWidget *self, void *data)
344
185
{
345
 
   //g_debug("cb_button_run()\n");
346
 
   gchar *cmdline;
 
186
   //g_print("cb_button_run()\n");
 
187
   gchar *argv[4];
347
188
 
348
189
   TrayApplet *ta = (TrayApplet *)data;
349
190
   HookDialog *hook_dialog = (HookDialog *)ta->user_data;
350
191
 
351
192
   /* mark the current hook file as run */
352
 
   HookFile *hf = g_object_get_data(G_OBJECT(self), "hook_file");
353
 
   mark_hook_file_as_run(hook_dialog, hf);
 
193
   gchar *hook_file = g_object_get_data(G_OBJECT(self), "hook_file");
 
194
   mark_hook_file_as_run(hook_dialog, (const char*)hook_file);
354
195
 
355
196
   gchar *cmd = g_object_get_data(G_OBJECT(self), "cmd");
356
197
   gchar *term = g_object_get_data(G_OBJECT(self), "term");
361
202
   }
362
203
 
363
204
   if(term != NULL && !g_ascii_strncasecmp(term, "true",-1)) {
364
 
      cmdline = g_strdup_printf("gnome-terminal -e %s",cmd);
365
 
   } else 
366
 
      cmdline = g_strdup(cmd);
367
 
 
368
 
   g_spawn_command_line_async(cmdline, NULL);
369
 
   g_free(cmdline);
 
205
      argv[0] = "xterm";
 
206
      argv[1] = "-e";
 
207
      argv[2] = cmd;
 
208
      argv[3] = NULL;
 
209
   } else {
 
210
      argv[0] = cmd;
 
211
      argv[1] = NULL;
 
212
   }
 
213
   g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH , 
 
214
                 NULL, NULL, NULL, NULL);
370
215
}
371
216
 
372
217
void cb_button_next(GtkWidget *self, void *data)
373
218
{
374
 
   g_debug("cb_button_next()");
 
219
   //g_print("cb_button_next()\n");
375
220
   TrayApplet *ta = (TrayApplet *)data;
376
221
   HookDialog *hook_dialog = (HookDialog *)ta->user_data;
377
222
 
378
 
   HookFile *hf;
379
 
   hf = (HookFile*)g_object_get_data(G_OBJECT(self),"HookFile");
380
 
   if(hf == NULL) {
381
 
      g_warning("button_next called without HookFile\n");
382
 
      return;
383
 
   }
384
 
   
385
 
   // mark as seen 
386
 
   hook_file_mark_as_seen(hook_dialog, hf);
387
 
   check_update_hooks(ta);
388
 
 
389
223
   if(hook_dialog->hook_files != NULL)
390
 
      show_next_hook(ta, hook_dialog->hook_files);
 
224
      show_one_hook(ta, hook_dialog->hook_files->data);
391
225
}
392
226
 
393
227
 
395
229
 
396
230
void show_hooks(TrayApplet *ta)
397
231
{
398
 
   g_debug("show_hooks()");
 
232
   //g_print("show_hooks()\n");
399
233
   HookDialog* hook_dialog = (HookDialog *)ta->user_data;
400
234
 
401
235
   GladeXML *xml = hook_dialog->glade_xml;
403
237
   assert(dia);
404
238
   GtkWidget *button_run = glade_xml_get_widget(xml, "button_run");
405
239
   assert(button_run);
406
 
   GtkWidget *button_next = glade_xml_get_widget(xml, "button_next");
407
 
   assert(button_next);
408
 
 
409
 
   // if show_next_hook() fails for some reason don't do anything
410
 
   if(!show_next_hook(ta, hook_dialog->hook_files))
411
 
      return;
412
 
 
 
240
 
 
241
   show_one_hook(ta, hook_dialog->hook_files->data);
 
242
  
 
243
   /* close dialog */
413
244
   int res = gtk_dialog_run(GTK_DIALOG(dia));
414
245
   if(res == GTK_RESPONSE_CLOSE) {
415
 
      // mark the currently current hookfile as seen
416
 
      HookFile *hf;
417
 
      hf = (HookFile*)g_object_get_data(G_OBJECT(button_next),"HookFile");
418
 
      if(hf == NULL) {
419
 
         g_warning("show_hooks called without HookFile\n");
420
 
         return;
421
 
      }
422
 
   
423
 
      // mark as seen 
424
 
      hook_file_mark_as_seen(hook_dialog, hf);
425
 
      check_update_hooks(ta);
 
246
      /* mark question as seen */
426
247
   }
427
 
 
428
248
   gtk_widget_hide(dia);
429
 
}
430
 
 
431
 
static gboolean
432
 
button_release_cb (GtkWidget *widget, 
433
 
                   GdkEventButton *event, 
434
 
                   TrayApplet *ta)
435
 
{
436
 
        if (event->button == 1 && event->type == GDK_BUTTON_RELEASE) {
437
 
           //g_debug("left click on hook applet\n");
438
 
           show_hooks(ta);
439
 
        }
440
 
        return TRUE;
441
 
}
442
 
 
443
 
gboolean is_hook_relevant(const gchar *hook_file)
444
 
{
445
 
   g_debug("is_hook_relevant()\n");
446
 
   gboolean res = TRUE;
447
 
 
448
 
   char *filename = g_strdup_printf("%s%s",HOOKS_DIR,hook_file);
449
 
   FILE *f = fopen(filename, "r");
450
 
   if(f == NULL) {
451
 
      // can't open, can't be relevant
452
 
      return FALSE; 
453
 
   }
454
 
   struct rfc822_header *rfc822 = rfc822_parse_stanza(f);
455
 
 
456
 
   // check the DontShowAfterReboot flag
457
 
   gchar *b = rfc822_header_lookup(rfc822, "DontShowAfterReboot");
458
 
   if(b != NULL && g_ascii_strncasecmp(b, "true",-1) == 0) {
459
 
 
460
 
      // read the uptime information
461
 
      double uptime=0, idle=0;
462
 
      char buf[1024];
463
 
      int fd = open("/proc/uptime", 0);
464
 
      int local_n = read(fd, buf, sizeof(buf)-1);
465
 
      buf[local_n] = '\0';
466
 
      char *savelocale = setlocale(LC_NUMERIC, NULL);
467
 
      setlocale(LC_NUMERIC,"C");
468
 
      sscanf(buf, "%lf %lf", &uptime,&idle);
469
 
      close(fd);
470
 
      setlocale(LC_NUMERIC,savelocale);
471
 
 
472
 
      time_t mtime = hook_file_time(hook_file);
473
 
      time_t now = time(NULL);
474
 
 
475
 
      g_debug("now: %i mtime: %i uptime: %f\n",now,mtime,uptime);
476
 
      g_debug("diff: %i  uptime: %f\n",now-mtime,uptime);
477
 
      if((int)uptime > 0 && (now - mtime) > (int)uptime) {
478
 
         g_debug("not relevant because of reboot: %s\n",hook_file);
479
 
         res = FALSE;
480
 
      }
481
 
   }
482
 
   fclose(f);
483
 
 
484
 
 
485
 
   g_free(filename);
486
 
   rfc822_header_free_all(rfc822);
487
 
   return res;
488
 
}
 
249
 
 
250
}
 
251
 
489
252
 
490
253
gboolean check_update_hooks(TrayApplet *ta)
491
254
{
492
 
   g_debug("check_update_hooks()");
 
255
   //g_print("check_update_hooks()\n");
493
256
 
494
257
   HookDialog *hook_dialog = (HookDialog*)ta->user_data;
495
258
 
500
263
   if(dir == NULL)
501
264
      g_critical("can't read %s directory\n",HOOKS_DIR);
502
265
 
503
 
   int unseen_count = 0;
504
266
   while((hook_file=g_dir_read_name(dir)) != NULL) {
505
 
 
506
 
      // check if the hook still applies (for e.g. DontShowAfterReboot)
507
 
      if(!is_hook_relevant(hook_file))
508
 
         continue;
509
 
 
510
 
      // see if we already know about this hook filename
511
267
      GList *elm = g_list_find_custom(hook_dialog->hook_files,hook_file,
512
 
                                      compare_hook_func);
513
 
 
514
 
      // not seen before, add to the list
515
 
      if(elm == NULL) {
516
 
         g_debug("never seen before: %s",hook_file);
517
 
         HookFile *t = g_new0(HookFile, 1);
518
 
         t->filename = strdup(hook_file);
519
 
         t->mtime = hook_file_time(hook_file);
520
 
         hook_file_md5(hook_file, t->md5);
521
 
         t->cmd_run = FALSE;
522
 
         t->seen = FALSE;
523
 
         hook_dialog->hook_files = g_list_append(hook_dialog->hook_files, t);
524
 
         // init elm with the just added record (will be needed below)
525
 
         elm = g_list_find_custom(hook_dialog->hook_files,hook_file,
526
 
                                  compare_hook_func);
527
 
         assert(elm != NULL);
528
 
      }
529
 
      
530
 
      // this is the hook file information we have (either because it was
531
 
      // availabe already or because we added it)
532
 
      HookFile *hf = (HookFile*)elm->data;
533
 
 
534
 
 
535
 
      // file has changed since we last saw it
536
 
      time_t new_mtime = hook_file_time(hook_file);
537
 
      if(new_mtime > hf->mtime) {
538
 
         g_debug("newer mtime: %s (%i > %i))",hook_file, new_mtime, hf->mtime);
539
 
         hf->seen = FALSE;
540
 
      }
541
 
 
542
 
      // we have not seen it yet (because e.g. it was just added)
543
 
      if(hf->seen == FALSE) {
544
 
 
545
 
         // update mtime (because we haven't seen the old one and there
546
 
         // is a new one now)
547
 
         hf->mtime = new_mtime;
548
 
 
549
 
         // check if there is already another notification that is 
550
 
         // a) not this one
551
 
         // b) not seen yet
552
 
         // c) the same
553
 
         // if so, we don't increase the unseen count as all identical
554
 
         // ones will maked as unseen at onces
555
 
         gboolean md5match = FALSE;
556
 
         GList *x = g_list_first(hook_dialog->hook_files);
557
 
         while(x!=NULL) {
558
 
            HookFile *e = (HookFile*)x->data;
559
 
            if((elm != x)  &&
560
 
               (e->seen == FALSE) &&
561
 
               (memcmp(hf->md5,e->md5,16)==0) )
562
 
              {
563
 
                 g_debug("%s (%s) was seen also in %s (%s)\n",
564
 
                         hf->filename, hf->md5, e->filename, e->md5);
565
 
                 md5match = TRUE;
566
 
              }
567
 
            x = g_list_next(x);
568
 
         }
569
 
         if(!md5match) {
570
 
            g_debug("%s increases unseen_count\n",hf->filename);
571
 
            unseen_count++;
572
 
         }
573
 
      }
574
 
 
575
 
 
 
268
                                      strcmp);
 
269
      if(hook_file_is_new(hook_dialog, hook_file)) {
 
270
         if(elm == NULL) {
 
271
            //g_print("check_update_hooks: appending: %s\n",hook_file);
 
272
            hook_dialog->hook_files = g_list_append(hook_dialog->hook_files, 
 
273
                                                    g_strdup(hook_file));
 
274
         }
 
275
      } else {
 
276
         if(elm != NULL) {
 
277
            //g_print("check_update_hooks: removing (seen): %s\n", hook_file);
 
278
            hook_dialog->hook_files = g_list_remove(hook_dialog->hook_files,
 
279
                                                    elm->data);
 
280
         }
 
281
      }
576
282
   }
577
283
   g_dir_close(dir);
578
284
 
579
 
   //g_debug("hooks: %i (new: %i)", g_list_length(hook_files), unseen_count);
 
285
   int num = g_list_length(hook_dialog->hook_files);
 
286
   //    g_print("check_update_hook() hook_files: %p %i \n", 
 
287
   //      hook_dialog->hook_files, num); 
580
288
 
581
289
   GladeXML *xml = hook_dialog->glade_xml;
582
290
   GtkWidget *button_next = glade_xml_get_widget(xml, "button_next");
583
 
   assert(button_next);
584
291
 
585
 
   switch(unseen_count) {
586
 
   case 0:
 
292
   if (num == 0) {
 
293
      //g_print("gtk_widget_hide() called on tray_icon\n");
587
294
      gtk_widget_hide(GTK_WIDGET(ta->tray_icon));
588
295
      gtk_widget_hide(button_next);
589
 
      break;
590
 
   case 1:
591
 
      gtk_widget_show(GTK_WIDGET(ta->tray_icon));
592
 
      gtk_widget_hide(button_next);
593
 
      break;
594
 
   default:
 
296
   } else {
 
297
      //g_print("gtk_widget_show() called on tray_icon\n");
 
298
      hooks_trayicon_update_tooltip (ta, num);
595
299
      gtk_widget_show(GTK_WIDGET(ta->tray_icon));
596
300
      gtk_widget_show(button_next);
597
 
      break;
598
301
   }
599
 
   hooks_trayicon_update_tooltip (ta, unseen_count);
600
302
 
601
303
   return TRUE;
602
304
}
603
305
 
604
 
void hook_read_seen_file(HookDialog *hook_dialog, const char* filename)
605
 
{
 
306
 
 
307
static gboolean
 
308
button_release_cb (GtkWidget *widget, 
 
309
                   GdkEventButton *event, 
 
310
                   TrayApplet *ta)
 
311
{
 
312
        if (event->button == 1 && event->type == GDK_BUTTON_RELEASE) {
 
313
           //g_print("left click on hook applet\n");
 
314
           show_hooks(ta);
 
315
        }
 
316
        return TRUE;
 
317
}
 
318
 
 
319
gboolean init_already_seen_hooks(TrayApplet *ta)
 
320
{
 
321
   HookDialog* hook_dialog = (HookDialog*)ta->user_data;
 
322
 
 
323
   GList *seen = hook_dialog->hook_files_seen;
 
324
   char *filename = g_strdup_printf("%s/"HOOKS_SEEN,g_get_home_dir());
606
325
   char buf[512];
607
326
   int time, was_run;
608
327
   FILE *f = fopen(filename, "r");
609
328
   if(f==NULL)
610
 
      return;
611
 
 
612
 
   g_debug("reading hook_file: %s \n", filename);
613
 
 
 
329
      return TRUE;
614
330
   while(fscanf(f, "%s %i %i",buf,&time,&was_run) == 3) {
615
 
 
616
 
      // first check if the file actually exists, if not skip it
617
 
      // (may already be delete when e.g. a package was removed)
618
 
      char *filename = g_strdup_printf("%s%s",HOOKS_DIR,buf);
619
 
      gboolean res = g_file_test(filename, G_FILE_TEST_EXISTS);
620
 
      g_free(filename);
621
 
      if(!res)
622
 
         continue;
623
 
 
624
 
      // now check if we already have that filename in the list
625
 
      GList *elm = g_list_find_custom(hook_dialog->hook_files,buf,
626
 
                                      compare_hook_func);
627
 
      if(elm != NULL) {
628
 
         g_debug("hookfile: %s already in the list", buf);
629
 
 
630
 
         // we have that file already in the list with a newer mtime,
631
 
         // than the file in the config file. ignore the config file
632
 
         HookFile *exisiting = (HookFile *)elm->data;
633
 
         // and it's more current
634
 
         if(exisiting->mtime > time) {
635
 
            g_debug("existing is newer, ignoring the read one\n");
636
 
            continue;
637
 
         }
638
 
 
639
 
         // we have it in the list, but the the file in the list is older
640
 
         // than the one in the config file. use this config-file instead
641
 
         // and update the values in the list
642
 
         exisiting->cmd_run = was_run;
643
 
         exisiting->seen = TRUE;
644
 
         exisiting->mtime = time;
645
 
         hook_file_md5(exisiting->filename,exisiting->md5);
646
 
 
647
 
      } else {
648
 
         // not in the list yet
649
 
         // add the just read hook file to the list
650
 
         g_debug("got: %s %i %i ",buf,time,was_run);
651
 
         HookFile *t = g_new0(HookFile, 1);
652
 
         t->filename = strdup(buf);
653
 
         t->mtime = time;
654
 
         t->cmd_run = was_run;
655
 
         t->seen = TRUE;
656
 
         hook_file_md5(t->filename,t->md5);
657
 
 
658
 
         hook_dialog->hook_files = g_list_append(hook_dialog->hook_files, t);
659
 
      }
 
331
      HookFileSeen *t = g_new0(HookFileSeen, 1);
 
332
      t->filename = strdup(buf);
 
333
      t->mtime = time;
 
334
      t->cmd_run = was_run;
 
335
      seen = g_list_append(seen, t);
 
336
      
 
337
      //g_print("got: %s %i %i \n",buf,time,was_run);
660
338
   }
 
339
   g_free(filename);
661
340
   fclose(f);
662
 
}
663
 
 
664
 
gboolean init_already_seen_hooks(TrayApplet *ta)
665
 
{
666
 
   g_debug("init_already_seen_hooks");
667
 
 
668
 
   HookDialog* hook_dialog = (HookDialog*)ta->user_data;
669
 
   char *filename;
670
 
 
671
 
   // init with default value
672
 
   hook_dialog->hook_files = NULL;  
673
 
 
674
 
   // read global hook file
675
 
   hook_read_seen_file(hook_dialog,GLOBAL_HOOKS_SEEN);
676
 
   
677
 
   // read user hook file
678
 
   filename = g_strdup_printf("%s/%s", g_get_home_dir(),HOOKS_SEEN);
679
 
   hook_read_seen_file(hook_dialog,filename);
680
 
   g_free(filename);
681
 
 
682
 
 
 
341
 
 
342
   hook_dialog->hook_files_seen = seen;
683
343
 
684
344
   return TRUE;
685
345
}
692
352
   
693
353
   GladeXML *xml = glade_xml_new(GLADEDIR"hooks-dialog.glade",  
694
354
                                 NULL, NULL);
695
 
   assert(xml);
696
355
   hook_dialog->glade_xml = xml;
697
356
   glade_xml_signal_connect_data(xml, "on_button_next_clicked", 
698
357
                                 G_CALLBACK(cb_button_next), 
701
360
                                 G_CALLBACK(cb_button_run), 
702
361
                                 (gpointer)ta);
703
362
 
704
 
   // setup a custom debug log handler
705
 
   g_log_set_handler (G_LOG_DOMAIN,
706
 
                      G_LOG_LEVEL_DEBUG,
707
 
                      debug_log_handler,
708
 
                      NULL);
709
 
 
710
 
 
711
363
   /* show dialog on click */
712
364
   g_signal_connect (G_OBJECT(ta->tray_icon),
713
365
                     "button-release-event",
714
366
                     G_CALLBACK (button_release_cb),
715
367
                     ta);
716
368
 
717
 
   // create a bold tag
718
 
   GtkWidget *text = glade_xml_get_widget(xml, "textview_hook");
719
 
   GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
720
 
   gtk_text_buffer_create_tag (buf, "bold_tag",
721
 
                               "scale", PANGO_SCALE_LARGE, 
722
 
                               "weight", PANGO_WEIGHT_BOLD,
723
 
                               NULL);  
724
 
 
725
 
 
726
369
   /* read already seen hooks */
727
370
   init_already_seen_hooks(ta);
728
371