1 /* Notification plugin for Claws Mail
2 * Copyright (C) 2005-2007 Holger Berndt
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 # include "claws-features.h"
21 #endif
22
23 #include "folder.h"
24 #include "folderview.h"
25 #include "codeconv.h"
26 #include "gtk/gtkutils.h"
27
28 #include "notification_core.h"
29 #include "notification_plugin.h"
30 #include "notification_prefs.h"
31 #include "notification_banner.h"
32 #include "notification_popup.h"
33 #include "notification_command.h"
34 #include "notification_lcdproc.h"
35 #include "notification_trayicon.h"
36 #include "notification_indicator.h"
37
38 #ifdef HAVE_LIBCANBERRA_GTK
39 # include <canberra-gtk.h>
40 #endif
41
42 typedef struct {
43 GSList *collected_msgs;
44 GSList *folder_items;
45 gboolean unread_also;
46 gint max_msgs;
47 gint num_msgs;
48 } TraverseCollect;
49
50 static gboolean notification_traverse_collect(GNode*, gpointer);
51 static void notification_new_unnotified_do_msg(MsgInfo*);
52 static gboolean notification_traverse_hash_startup(GNode*, gpointer);
53
54 static GHashTable *msg_count_hash;
55 static NotificationMsgCount msg_count;
56
57 #ifdef HAVE_LIBCANBERRA_GTK
58 static gboolean canberra_new_email_is_playing = FALSE;
59 #endif
60
61 static void msg_count_hash_update_func(FolderItem*, gpointer);
62 static void msg_count_update_from_hash(gpointer, gpointer, gpointer);
63 static void msg_count_clear(NotificationMsgCount*);
64 static void msg_count_add(NotificationMsgCount*,NotificationMsgCount*);
65 static void msg_count_copy(NotificationMsgCount*,NotificationMsgCount*);
66
notification_core_global_includes_changed(void)67 void notification_core_global_includes_changed(void)
68 {
69 #ifdef NOTIFICATION_BANNER
70 notification_update_banner();
71 #endif
72
73 if(msg_count_hash) {
74 g_hash_table_destroy(msg_count_hash);
75 msg_count_hash = NULL;
76 }
77 notification_update_msg_counts(NULL);
78 }
79
80 /* Hide/show main window */
notification_toggle_hide_show_window(void)81 void notification_toggle_hide_show_window(void)
82 {
83 MainWindow *mainwin;
84 GdkWindow *gdkwin;
85
86 if((mainwin = mainwindow_get_mainwindow()) == NULL)
87 return;
88
89 gdkwin = gtk_widget_get_window(GTK_WIDGET(mainwin->window));
90 if(gtk_widget_get_visible(GTK_WIDGET(mainwin->window))) {
91 if((gdk_window_get_state(gdkwin) & GDK_WINDOW_STATE_ICONIFIED)
92 || mainwindow_is_obscured()) {
93 notification_show_mainwindow(mainwin);
94 }
95 else {
96 main_window_hide(mainwin);
97 }
98 }
99 else {
100 notification_show_mainwindow(mainwin);
101 }
102 }
103
notification_update_msg_counts(FolderItem * removed_item)104 void notification_update_msg_counts(FolderItem *removed_item)
105 {
106 if(!msg_count_hash)
107 msg_count_hash = g_hash_table_new_full(g_str_hash,g_str_equal,
108 g_free,g_free);
109
110 folder_func_to_all_folders(msg_count_hash_update_func, msg_count_hash);
111
112 if(removed_item) {
113 gchar *identifier;
114 identifier = folder_item_get_identifier(removed_item);
115 if(identifier) {
116 g_hash_table_remove(msg_count_hash, identifier);
117 g_free(identifier);
118 }
119 }
120 msg_count_clear(&msg_count);
121 g_hash_table_foreach(msg_count_hash, msg_count_update_from_hash, NULL);
122 #ifdef NOTIFICATION_LCDPROC
123 notification_update_lcdproc();
124 #endif
125 #ifdef NOTIFICATION_TRAYICON
126 notification_update_trayicon();
127 #endif
128 #ifdef NOTIFICATION_INDICATOR
129 notification_update_indicator();
130 #endif
131 notification_update_urgency_hint();
132 }
133
msg_count_clear(NotificationMsgCount * count)134 static void msg_count_clear(NotificationMsgCount *count)
135 {
136 count->new_msgs = 0;
137 count->unread_msgs = 0;
138 count->unreadmarked_msgs = 0;
139 count->marked_msgs = 0;
140 count->total_msgs = 0;
141 }
142
143 /* c1 += c2 */
msg_count_add(NotificationMsgCount * c1,NotificationMsgCount * c2)144 static void msg_count_add(NotificationMsgCount *c1,NotificationMsgCount *c2)
145 {
146 c1->new_msgs += c2->new_msgs;
147 c1->unread_msgs += c2->unread_msgs;
148 c1->unreadmarked_msgs += c2->unreadmarked_msgs;
149 c1->marked_msgs += c2->marked_msgs;
150 c1->total_msgs += c2->total_msgs;
151 }
152
153 /* c1 = c2 */
msg_count_copy(NotificationMsgCount * c1,NotificationMsgCount * c2)154 static void msg_count_copy(NotificationMsgCount *c1,NotificationMsgCount *c2)
155 {
156 c1->new_msgs = c2->new_msgs;
157 c1->unread_msgs = c2->unread_msgs;
158 c1->unreadmarked_msgs = c2->unreadmarked_msgs;
159 c1->marked_msgs = c2->marked_msgs;
160 c1->total_msgs = c2->total_msgs;
161 }
162
get_flat_gslist_from_nodes_traverse_func(GNode * node,gpointer data)163 gboolean get_flat_gslist_from_nodes_traverse_func(GNode *node, gpointer data)
164 {
165 if(node->data) {
166 GSList **list = data;
167 *list = g_slist_prepend(*list, node->data);
168 }
169 return FALSE;
170 }
171
get_flat_gslist_from_nodes(GNode * node)172 GSList* get_flat_gslist_from_nodes(GNode *node)
173 {
174 GSList *retval = NULL;
175
176 g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, get_flat_gslist_from_nodes_traverse_func, &retval);
177 return retval;
178 }
179
notification_core_get_msg_count_of_foldername(gchar * foldername,NotificationMsgCount * count)180 void notification_core_get_msg_count_of_foldername(gchar *foldername, NotificationMsgCount *count)
181 {
182 GList *list;
183 GSList *f_list;
184
185 Folder *walk_folder;
186 Folder *folder = NULL;
187
188 for(list = folder_get_list(); list != NULL; list = list->next) {
189 walk_folder = list->data;
190 if(g_strcmp0(foldername, walk_folder->name) == 0) {
191 folder = walk_folder;
192 break;
193 }
194 }
195 if(!folder) {
196 debug_print("Notification plugin: Error: Could not find folder %s\n", foldername);
197 return;
198 }
199
200 msg_count_clear(count);
201 f_list = get_flat_gslist_from_nodes(folder->node);
202 notification_core_get_msg_count(f_list, count);
203 g_slist_free(f_list);
204 }
205
notification_core_get_msg_count(GSList * folder_list,NotificationMsgCount * count)206 void notification_core_get_msg_count(GSList *folder_list,
207 NotificationMsgCount *count)
208 {
209 GSList *walk;
210
211 if(!folder_list)
212 msg_count_copy(count,&msg_count);
213 else {
214 msg_count_clear(count);
215 for(walk = folder_list; walk; walk = walk->next) {
216 gchar *identifier;
217 NotificationMsgCount *item_count;
218 FolderItem *item = (FolderItem*) walk->data;
219 identifier = folder_item_get_identifier(item);
220 if(identifier) {
221 item_count = g_hash_table_lookup(msg_count_hash,identifier);
222 g_free(identifier);
223 if(item_count)
224 msg_count_add(count, item_count);
225 }
226 }
227 }
228 }
229
msg_count_hash_update_func(FolderItem * item,gpointer data)230 static void msg_count_hash_update_func(FolderItem *item, gpointer data)
231 {
232 gchar *identifier;
233 NotificationMsgCount *count;
234 GHashTable *hash = data;
235
236 if(!notify_include_folder_type(item->folder->klass->type,
237 item->folder->klass->uistr))
238 return;
239
240 identifier = folder_item_get_identifier(item);
241 if(!identifier)
242 return;
243
244 count = g_hash_table_lookup(hash, identifier);
245
246 if(!count) {
247 count = g_new0(NotificationMsgCount,1);
248 g_hash_table_insert(hash, identifier, count);
249 }
250 else
251 g_free(identifier);
252
253 count->new_msgs = item->new_msgs;
254 count->unread_msgs = item->unread_msgs;
255 count->unreadmarked_msgs = item->unreadmarked_msgs;
256 count->marked_msgs = item->marked_msgs;
257 count->total_msgs = item->total_msgs;
258 }
259
msg_count_update_from_hash(gpointer key,gpointer value,gpointer data)260 static void msg_count_update_from_hash(gpointer key, gpointer value,
261 gpointer data)
262 {
263 NotificationMsgCount *count = value;
264 msg_count_add(&msg_count,count);
265 }
266
267
268 /* Replacement for the post-filtering hook:
269 Pseudocode by Colin:
270 hook on FOLDER_ITEM_UPDATE_HOOKLIST
271 if hook flags & F_ITEM_UPDATE_MSGCOUNT
272 scan mails (folder_item_get_msg_list)
273 if MSG_IS_NEW(msginfo->flags) and not in hashtable
274 notify()
275 add to hashtable
276 procmsg_msg_list_free
277
278 hook on MSGINFO_UPDATE_HOOKLIST
279 if hook flags & MSGINFO_UPDATE_FLAGS
280 if !MSG_IS_NEW(msginfo->flags)
281 remove from hashtable, it's now useless
282 */
283
284 /* This hash table holds all mails that we already notified about,
285 and that still are marked as "new". The keys are the msgid's,
286 the values are just 1's stored in a pointer. */
287 static GHashTable *notified_hash = NULL;
288
289
290 /* Remove message from the notified_hash if
291 * - the message flags changed
292 * - the message is not new
293 * - the message is in the hash
294 */
notification_notified_hash_msginfo_update(MsgInfoUpdate * msg_update)295 gboolean notification_notified_hash_msginfo_update(MsgInfoUpdate *msg_update)
296 {
297 g_return_val_if_fail(msg_update != NULL, FALSE);
298
299 if((msg_update->flags & MSGINFO_UPDATE_FLAGS) &&
300 !MSG_IS_NEW(msg_update->msginfo->flags)) {
301
302 MsgInfo *msg;
303 gchar *msgid;
304
305 msg = msg_update->msginfo;
306 if(msg->msgid)
307 msgid = msg->msgid;
308 else {
309 debug_print("Notification Plugin: Message has no message ID!\n");
310 msgid = "";
311 }
312
313 g_return_val_if_fail(msg != NULL, FALSE);
314
315 if(g_hash_table_lookup(notified_hash, msgid) != NULL) {
316
317 debug_print("Notification Plugin: Removing message id %s from hash "
318 "table\n", msgid);
319 g_hash_table_remove(notified_hash, msgid);
320 }
321 }
322 return FALSE;
323 }
324
325 /* On startup, mark all new mails as already notified
326 * (by including them in the hash) */
notification_notified_hash_startup_init(void)327 void notification_notified_hash_startup_init(void)
328 {
329 GList *folder_list, *walk;
330 Folder *folder;
331
332 if(!notified_hash) {
333 notified_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
334 g_free, NULL);
335 debug_print("Notification Plugin: Hash table created\n");
336 }
337
338 folder_list = folder_get_list();
339 for(walk = folder_list; walk != NULL; walk = g_list_next(walk)) {
340 folder = walk->data;
341
342 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
343 notification_traverse_hash_startup, NULL);
344 }
345 }
346
notification_traverse_hash_startup(GNode * node,gpointer data)347 static gboolean notification_traverse_hash_startup(GNode *node, gpointer data)
348 {
349 GSList *walk;
350 GSList *msg_list;
351 FolderItem *item = (FolderItem*) node->data;
352 gint new_msgs_left;
353
354 if(!(item->new_msgs))
355 return FALSE;
356
357 new_msgs_left = item->new_msgs;
358 msg_list = folder_item_get_msg_list(item);
359
360 for(walk = msg_list; walk; walk = g_slist_next(walk)) {
361 MsgInfo *msg = (MsgInfo*) walk->data;
362 if(MSG_IS_NEW(msg->flags)) {
363 gchar *msgid;
364
365 if(msg->msgid)
366 msgid = msg->msgid;
367 else {
368 debug_print("Notification Plugin: Message has no message ID!\n");
369 msgid = "";
370 }
371
372 /* If the message id is not yet in the hash, add it */
373 g_hash_table_insert(notified_hash, g_strdup(msgid),
374 GINT_TO_POINTER(1));
375 debug_print("Notification Plugin: Init: Added msg id %s to the hash\n",
376 msgid);
377 /* Decrement left count and check if we're already done */
378 new_msgs_left--;
379 if(new_msgs_left == 0)
380 break;
381 }
382 }
383 procmsg_msg_list_free(msg_list);
384 return FALSE;
385 }
386
notification_core_free(void)387 void notification_core_free(void)
388 {
389 if(notified_hash) {
390 g_hash_table_destroy(notified_hash);
391 notified_hash = NULL;
392 }
393 if(msg_count_hash) {
394 g_hash_table_destroy(msg_count_hash);
395 msg_count_hash = NULL;
396 }
397 debug_print("Notification Plugin: Freed internal data\n");
398 }
399
notification_new_unnotified_msgs(FolderItemUpdateData * update_data)400 void notification_new_unnotified_msgs(FolderItemUpdateData *update_data)
401 {
402 GSList *msg_list, *walk;
403
404 g_return_if_fail(notified_hash != NULL);
405
406 msg_list = folder_item_get_msg_list(update_data->item);
407
408 for(walk = msg_list; walk; walk = g_slist_next(walk)) {
409 MsgInfo *msg;
410 msg = (MsgInfo*) walk->data;
411
412 if(MSG_IS_NEW(msg->flags)) {
413 gchar *msgid;
414
415 if(msg->msgid)
416 msgid = msg->msgid;
417 else {
418 debug_print("Notification Plugin: Message has not message ID!\n");
419 msgid = "";
420 }
421
422 debug_print("Notification Plugin: Found msg %s, "
423 "checking if it is in hash...\n", msgid);
424 /* Check if message is in hash table */
425 if(g_hash_table_lookup(notified_hash, msgid) != NULL)
426 debug_print("yes.\n");
427 else {
428 /* Add to hashtable */
429 g_hash_table_insert(notified_hash, g_strdup(msgid),
430 GINT_TO_POINTER(1));
431 debug_print("no, added to table.\n");
432
433 /* Do the notification */
434 notification_new_unnotified_do_msg(msg);
435 }
436
437 } /* msg is 'new' */
438 } /* for all messages */
439 procmsg_msg_list_free(msg_list);
440 }
441
442 #ifdef HAVE_LIBCANBERRA_GTK
canberra_finished_cb(ca_context * c,uint32_t id,int error,void * data)443 static void canberra_finished_cb(ca_context *c, uint32_t id, int error, void *data)
444 {
445 canberra_new_email_is_playing = FALSE;
446 }
447 #endif
448
notification_new_unnotified_do_msg(MsgInfo * msg)449 static void notification_new_unnotified_do_msg(MsgInfo *msg)
450 {
451 #ifdef NOTIFICATION_POPUP
452 notification_popup_msg(msg);
453 #endif
454 #ifdef NOTIFICATION_COMMAND
455 notification_command_msg(msg);
456 #endif
457 #ifdef NOTIFICATION_TRAYICON
458 notification_trayicon_msg(msg);
459 #endif
460
461 #ifdef HAVE_LIBCANBERRA_GTK
462 /* canberra */
463 if(notify_config.canberra_play_sounds && !canberra_new_email_is_playing) {
464 ca_proplist *proplist;
465 ca_proplist_create(&proplist);
466 ca_proplist_sets(proplist,CA_PROP_EVENT_ID ,"message-new-email");
467 canberra_new_email_is_playing = TRUE;
468 ca_context_play_full(ca_gtk_context_get(), 0, proplist, canberra_finished_cb, NULL);
469 ca_proplist_destroy(proplist);
470 }
471 #endif
472 }
473
474 /* If folders is not NULL, then consider only those folder items
475 * If max_msgs is not 0, stop after collecting msg_msgs messages
476 */
notification_collect_msgs(gboolean unread_also,GSList * folder_items,gint max_msgs)477 GSList* notification_collect_msgs(gboolean unread_also, GSList *folder_items,
478 gint max_msgs)
479 {
480 GList *folder_list, *walk;
481 Folder *folder;
482 TraverseCollect collect_data;
483
484 collect_data.unread_also = unread_also;
485 collect_data.collected_msgs = NULL;
486 collect_data.folder_items = folder_items;
487 collect_data.max_msgs = max_msgs;
488 collect_data.num_msgs = 0;
489
490 folder_list = folder_get_list();
491 for(walk = folder_list; walk != NULL; walk = g_list_next(walk)) {
492 folder = walk->data;
493
494 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
495 notification_traverse_collect, &collect_data);
496 }
497 return collect_data.collected_msgs;
498 }
499
notification_collected_msgs_free(GSList * collected_msgs)500 void notification_collected_msgs_free(GSList *collected_msgs)
501 {
502 if(collected_msgs) {
503 GSList *walk;
504 for(walk = collected_msgs; walk != NULL; walk = g_slist_next(walk)) {
505 CollectedMsg *msg = walk->data;
506 if(msg->from)
507 g_free(msg->from);
508 if(msg->subject)
509 g_free(msg->subject);
510 if(msg->folderitem_name)
511 g_free(msg->folderitem_name);
512 msg->msginfo = NULL;
513 g_free(msg);
514 }
515 g_slist_free(collected_msgs);
516 }
517 }
518
notification_traverse_collect(GNode * node,gpointer data)519 static gboolean notification_traverse_collect(GNode *node, gpointer data)
520 {
521 TraverseCollect *cdata = data;
522 FolderItem *item = node->data;
523 gchar *folder_id_cur;
524
525 /* Obey global folder type limitations */
526 if(!notify_include_folder_type(item->folder->klass->type,
527 item->folder->klass->uistr))
528 return FALSE;
529
530 /* If a folder_items list was given, check it first */
531 if((cdata->folder_items) && (item->path != NULL) &&
532 ((folder_id_cur = folder_item_get_identifier(item)) != NULL)) {
533 FolderItem *list_item;
534 GSList *walk;
535 gchar *folder_id_list;
536 gboolean eq;
537 gboolean folder_in_list = FALSE;
538
539 for(walk = cdata->folder_items; walk != NULL; walk = g_slist_next(walk)) {
540 list_item = walk->data;
541 folder_id_list = folder_item_get_identifier(list_item);
542 eq = !g_strcmp0(folder_id_list,folder_id_cur);
543 g_free(folder_id_list);
544 if(eq) {
545 folder_in_list = TRUE;
546 break;
547 }
548 }
549 g_free(folder_id_cur);
550 if(!folder_in_list)
551 return FALSE;
552 }
553
554 if(item->new_msgs || (cdata->unread_also && item->unread_msgs)) {
555 GSList *msg_list = folder_item_get_msg_list(item);
556 GSList *walk;
557 for(walk = msg_list; walk != NULL; walk = g_slist_next(walk)) {
558 MsgInfo *msg_info = walk->data;
559 CollectedMsg *cmsg;
560
561 if((cdata->max_msgs != 0) && (cdata->num_msgs >= cdata->max_msgs))
562 return FALSE;
563
564 if(MSG_IS_NEW(msg_info->flags) ||
565 (MSG_IS_UNREAD(msg_info->flags) && cdata->unread_also)) {
566
567 cmsg = g_new(CollectedMsg, 1);
568 cmsg->from = g_strdup(msg_info->from ? msg_info->from : "");
569 cmsg->subject = g_strdup(msg_info->subject ? msg_info->subject : "");
570 if(msg_info->folder && msg_info->folder->name)
571 cmsg->folderitem_name = g_strdup(msg_info->folder->path);
572 else
573 cmsg->folderitem_name = g_strdup("");
574
575 cmsg->msginfo = msg_info;
576
577 cdata->collected_msgs = g_slist_prepend(cdata->collected_msgs, cmsg);
578 cdata->num_msgs++;
579 }
580 }
581 procmsg_msg_list_free(msg_list);
582 }
583
584 return FALSE;
585 }
586
notify_include_folder_type(FolderType ftype,gchar * uistr)587 gboolean notify_include_folder_type(FolderType ftype, gchar *uistr)
588 {
589 gboolean retval;
590
591 retval = FALSE;
592 switch(ftype) {
593 case F_MH:
594 case F_MBOX:
595 case F_MAILDIR:
596 case F_IMAP:
597 if(notify_config.include_mail)
598 retval = TRUE;
599 break;
600 case F_NEWS:
601 if(notify_config.include_news)
602 retval = TRUE;
603 break;
604 case F_UNKNOWN:
605 if(uistr == NULL)
606 retval = FALSE;
607 else if(!strcmp(uistr, "vCalendar")) {
608 if(notify_config.include_calendar)
609 retval = TRUE;
610 }
611 else if(!strcmp(uistr, "RSSyl")) {
612 if(notify_config.include_rss)
613 retval = TRUE;
614 }
615 else
616 debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
617 break;
618 default:
619 debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
620 }
621
622 return retval;
623 }
624
fix_folderview_scroll(MainWindow * mainwin)625 static void fix_folderview_scroll(MainWindow *mainwin)
626 {
627 static gboolean fix_done = FALSE;
628
629 if (fix_done)
630 return;
631
632 gtk_widget_queue_resize(mainwin->folderview->ctree);
633
634 fix_done = TRUE;
635 }
636
notification_show_mainwindow(MainWindow * mainwin)637 void notification_show_mainwindow(MainWindow *mainwin)
638 {
639 gtk_window_deiconify(GTK_WINDOW(mainwin->window));
640 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mainwin->window), FALSE);
641 main_window_show(mainwin);
642 gtk_window_present(GTK_WINDOW(mainwin->window));
643 fix_folderview_scroll(mainwin);
644 }
645
646 #ifdef HAVE_LIBNOTIFY
647 #define STR_MAX_LEN 511
648 /* Returns a newly allocated string which needs to be freed */
notification_libnotify_sanitize_str(gchar * in)649 gchar* notification_libnotify_sanitize_str(gchar *in)
650 {
651 gint out;
652 gchar tmp_str[STR_MAX_LEN+1];
653
654 if(in == NULL) return NULL;
655
656 out = 0;
657 while(*in) {
658 if(*in == '<') {
659 if(out+4 > STR_MAX_LEN) break;
660 memcpy(&(tmp_str[out]),"<",4);
661 in++; out += 4;
662 }
663 else if(*in == '>') {
664 if(out+4 > STR_MAX_LEN) break;
665 memcpy(&(tmp_str[out]),">",4);
666 in++; out += 4;
667 }
668 else if(*in == '&') {
669 if(out+5 > STR_MAX_LEN) break;
670 memcpy(&(tmp_str[out]),"&",5);
671 in++; out += 5;
672 }
673 else {
674 if(out+1 > STR_MAX_LEN) break;
675 tmp_str[out++] = *in++;
676 }
677 }
678 tmp_str[out] = '\0';
679 return strdup(tmp_str);
680 }
681
notification_validate_utf8_str(gchar * text)682 gchar* notification_validate_utf8_str(gchar *text)
683 {
684 gchar *utf8_str = NULL;
685
686 if(!g_utf8_validate(text, -1, NULL)) {
687 debug_print("Notification plugin: String is not valid utf8, "
688 "trying to fix it...\n");
689 /* fix it */
690 utf8_str = conv_codeset_strdup(text,
691 conv_get_locale_charset_str_no_utf8(),
692 CS_INTERNAL);
693 /* check if the fix worked */
694 if(utf8_str == NULL || !g_utf8_validate(utf8_str, -1, NULL)) {
695 debug_print("Notification plugin: String is still not valid utf8, "
696 "sanitizing...\n");
697 utf8_str = g_malloc(strlen(text)*2+1);
698 conv_localetodisp(utf8_str, strlen(text)*2+1, text);
699 }
700 }
701 else {
702 debug_print("Notification plugin: String is valid utf8\n");
703 utf8_str = g_strdup(text);
704 }
705 return utf8_str;
706 }
707 #endif
708